Global state :: Context api, redux, mobx, swr

recoil이 나오기 전에 사용하던 Global state

props drilling

global state가 나오기 전에 state를 공유하던 방법

  • 부모가 가지고 있는 state를 최하위에 있는 자식 컴포넌트에 props로 넘겨주려고 하려면
    중간 중간에 있는 모든 자식 컴포넌트에게도 넘겨줘야 한다.
  • 사용하지 않을 컴포넌트에서도 props를 받아서 넘기는 작업을 해야하기 때문에 비효율적이다.
  • props를 드릴처럼 뚫고 내려간다고 해서 props drilling이라고 한다.

global state

props drilling 없이(중간 중간마다 있는 자식 컴포넌트들에게 props를 전달하지 않고도) 모든 컴포넌트에서 공통적으로 공유할 수 있는 state

1. Context-api

Context를 이용하면, props drilling 없이 가장 최상위에서 모든 State들을 관리해서 어디서든 State를 가져올 수 있다.

단점

  • 불필요한 렌더링
    아래의 4번 단계에서 provider로 감싸진 부분의 업데이트가 되지 않은 state에도 리렌더가 일어난다.
    👉🏻 이를 보완해서 나온 것이 Recoil⭐️

사용 방법

  1. 최상위 컴포넌트 _app.tsx에서 모든 컴포넌트로 전달해줄 State를 담는 Context를 설정한다.
    react에서 제공하는 createContext를 사용해서 생성한다.

  2. Context 데이터를 사용할 변수에 createContext 함수의 인자값으로 관리할 State들을 객체 형태로 담아준다.

  3. useState를 이용해 설정한 State 값들을 만들어준다.

  4. return문에서 전체 페이지를 감싸는 태그를 추가한다.
    value에 전체 페이지로 전달할 State를 넣는다.
    여기에 넣은 state들이 전역 state가 된다.

  5. 사용하려는 페이지에서 useContext를 사용해서 불러온다.

2. redux

[Docs]

  • JS 앱을 위한 예측 가능한 상태 컨테이너
    (react뿐만 아니라, Angular, jQuery, vanilla JS 등에서도 작동 가능하다.)

  • store라는 하나의 데이터 공간에 global state를 포함한 모든 state를 저장한다.
    (api로 받아오는 데이터든 만든 데이터든 모든 state를 전부 다 redux에 담아서 사용)

  • 액션 객체를 통해서만 상태를 변경할 수 있다.

초창기에는 react를 사용할 때 redux가 필수적으로 사용되었다.

하지만, 세팅도 오래걸리고, 만들어야 하는 것도 많고,, 노가다성 코드가 많았다.

이후에 이를 개선해서 MobX, swr, react-query 등의 라이브러리가 나왔다.

3. MobX

[Docs]

  • 독립적인 라이브러리이지만 대부분 React와 함께 사용된다.

  • 상태에 따라 필요한 경우에만 연산이 실행된다.

  • Redux에 비해 읽기 쉽고 추론하기도 쉽다.

4. SWR

[Docs]

  • 데이터 가져오기를 위한 React Hooks

  • 캐시로부터 데이터를 반환한 후, fetch 요청(재검증)을 하고, 최종적으로 최신화된 데이터를 가져온다.

사용 방법

  • useSWR hook을 이용한다.

  • fetcher 함수는 데이터를 반환하는 어떠한 비동기 함수도 될 수 있다.
    네이티브 fetch 또는 Axios와 같은 도구를 사용한다.

  • 요청의 상태에 기반한 data와 error를 반환한다.

/* 재사용 가능한 데이터 hook 만들기 */
function useUser (id) {
  const { data, error } = useSWR(`/api/user/${id}`, fetcher)

  return {
    user: data,
    isLoading: !error && !data,
    isError: error
  }
}

/* 컴포넌트에서 사용하기 */
function Avatar ({ id }) {
  const { user, isLoading, isError } = useUser(id)

  if (isLoading) return <Spinner />
  if (isError) return <Error />
  return <img src={user.avatar} />
}

좋은 웹페이지 즐겨찾기