본문 바로가기
개발/React

리액트 - SWR로 상태 관리하기 (Managing State with SWR)

by 피로물든딸기 2024. 3. 22.
반응형

리액트 전체 링크

 

참고

- https://swr.vercel.app/ko

 

리덕스로 상태 관리하기
- Context API로 상태 관리하기
- recoil로 상태 관리하기
- SWR로 상태 관리하기

 

props useState에 정의된 값을 넘겨주면, 하위 컴포넌트에서 상태를 관리할 수 있다.

예시 코드는 다음과 같다.

// ParentComponent.js
import React, { useState } from "react";
import ChildComponent from "./ChildComponent";

const ParentComponent = () => {
  const [value, setValue] = useState(0);
  return (
    <div>
      <h2>Parent Component</h2>
      <button onClick={() => setValue(value + 1)}>Parent +</button>
      <p>{`Parent value : ${value}`}</p>
      <ChildComponent value={value} setValue={setValue} />
    </div>
  );
};

export default ParentComponent;

 

자식 컴포넌트는 다음과 같다.

// ChildComponent.js
import React from 'react';
import GrandChildComponent from './GrandChildComponent';

const ChildComponent = ({ value, setValue }) => {
  return (
    <div>
      <h3>Child Component</h3>
      <button onClick={() => setValue(value + 1)}>Child +</button>
      <p>{`Child value : ${value}`}</p>
      <GrandChildComponent value={value} setValue={setValue}/>
    </div>
  );
}

export default ChildComponent;

 

손자 컴포넌트는 다음과 같다.

// GrandChildComponent.js
import React from 'react';

const GrandChildComponent = ({ value, setValue }) => {
  return (
    <div>
      <h4>Grandchild Component</h4>
      <button onClick={() => setValue(value + 1)}>Grandchild +</button>
      <p>{`Grandchild value : ${value}`}</p>      
    </div>
  );
}

export default GrandChildComponent;

 

이제 value가 모든 컴포넌트에서 연동된다.

만약 ChildComponent value에 대한 상태를 알 필요가 없거나, 하이어라키가 복잡해지면 상태 관리가 어려워진다.


SWR 적용하기

 

SWR을 사용하기 위해 라이브러리를 설치하자.

npm install swr

 

SWR에는 여러 옵션이 있고, 사용 방법도 다양하지만 여기서는 간단한 Counter만 만든다. (링크 참고)

 

예시는 다음과 같다.

key, default, 그리고 fetcheruseSWR로 넘겨서 data, error, isLoading, mutate를 얻는다.

  const { data, error, isLoading, mutate } = useSWR(
    "/api/value",
    { fallbackData: { value: 0 } }, // default value
    fetcher
  );

 

SWRerror가 발생했거나, 로딩 중인 경우 처리가 가능하다.

  if (error) return "An error has occurred. " + error;
  if (isLoading) return "Loading...";

 

fetcher의 예시는 다음과 같다.

const fetcher = (url) => fetch(url).then((res) => res.json());

 

또한 axios를 사용하는 것도 가능하다.

import axios from "axios";

const fetcher = (url) => axios.get(url).then((res) => res.data);

 

값을 변경하고 싶다면 button에서 mutate를 이용하면 된다.

// ParentComponent.js
import React, { useState } from "react";
import useSWR from "swr";
import ChildComponent from "./ChildComponent";

//import axios from "axios";
//const fetcher = (url) => axios.get(url).then((res) => res.data);
const fetcher = (url) => fetch(url).then((res) => res.json());

const ParentComponent = () => {
  const { data, error, isLoading, mutate } = useSWR(
    "/api/value",
    { fallbackData: { value: 0 } }, // default value
    fetcher
  );

  if (error) return "An error has occurred. " + error;
  if (isLoading) return "Loading...";

  return (
    <div>
      <h2>Parent Component</h2>
      <button onClick={() => mutate({ value: data.value + 1 })}>
        Parent +
      </button>
      <p>{`Parent value : ${data.value}`}</p>
      <ChildComponent />
    </div>
  );
};

export default ParentComponent;

 

ChildComponent는 상태를 관리하지 않는다.

// ChildComponent.js
import React from 'react';
import GrandChildComponent from './GrandChildComponent';

const ChildComponent = () => {
  return (
    <div>
      <h3>Child Component</h3>
      <GrandChildComponent />
    </div>
  );
}

export default ChildComponent;

 

GrandChildComponent에도 useSWR을 적용하자.

// GrandChildComponent.js
import React from "react";
import useSWR from "swr";

//import axios from "axios";
//const fetcher = (url) => axios.get(url).then((res) => res.data);
const fetcher = (url) => fetch(url).then((res) => res.json());

const GrandChildComponent = () => {
  const { data, error, isLoading, mutate } = useSWR(
    "/api/value",
    { fallbackData: { value: 0 } }, // default value
    fetcher
  );

  if (error) return "An error has occurred. " + error;
  if (isLoading) return "Loading...";

  return (
    <div>
      <h4>Grandchild Component</h4>
      <button onClick={() => mutate({ value: data.value + 1 })}>
        Grandchild +
      </button>
      <p>{`Grandchild value : ${data.value}`}</p>
    </div>
  );
};

export default GrandChildComponent;

 

이제 ChildComponent value를 넘겨받지 않아도 GrandChildComponent는 정상적으로 상태를 관리한다.

반응형

댓글