[React] useReducer와 useContext를 사용한 전역 상태관리

Joowon Jang·2024년 11월 22일
0

React

목록 보기
15/19

라이브러리 의존도를 줄이면서도, 체계를 한 번 이해하고 나면 깔끔하게 상태를 관리할 수 있는 방법을 알게 되어 정리해보았다.

전역 상태 관리?

많은 사람들이 전역 상태를 관리할 때, Redux, Zustand같은 라이브러리를 사용해 비교적 쉽게 코드를 작성하고, 나도 Zustand가 간편해서 개인적으로 좋아하는 라이브러리이다.
하지만, useReducer와 useContext를 사용하면, 라이브러리를 사용하지 않고도 비슷한 방식으로 전역 상태를 관리할 수 있다.

useContext
https://velog.io/@juwon98/React-useContext
useReducer와 리듀서 패턴
https://velog.io/@juwon98/React-useReducer

useReducer + useContext로 상태 관리

간단한 유저 로그인 상태 관리를 예시로 정리해보자.
주석으로 코드의 흐름을 정리해 두었다.

reducer 함수를 작성해 둔 store

// authStore.js

// 유저 초기 상태
export const INITIAL_AUTH_INFO = {
  user: null,
  token: null,
};

// dispatch의 action 타입 (2가지로 정의)
const ACTION_TYPES = {
  SET: 'set_auth',
  RESET: 'reset_auth',
};

// 유저 정보 저장을 위한 (dispatch에 사용할) action 객체 생성 함수
export const setAuth = (authInfo) => ({
  type: ACTION_TYPES.SET,
  payload: authInfo,
});
// 유저 정보 삭제를 위한 (dispatch에 사용할) action 객체 생성 함수
export const resetAuth = () => ({
  type: ACTION_TYPES.RESET,
});

// 리듀서 함수 (set, reset 두 가지 업데이트를 지원)
const authReducer = (state, action) => {
  switch (action.type) {
    // 유저 정보 저장
    case ACTION_TYPES.SET: {
      const authInfo = action.payload;
      localStorage.setItem('auth_info', JSON.stringify(authInfo));
      return { ...state, ...authInfo };
    }
	// 유저 정보 삭제
    case ACTION_TYPES.RESET: {
      localStorage.removeItem('auth_info');
      return INITIAL_AUTH_INFO;
    }

    default:
      return state;
  }
};

export default authReducer;

useReducer와 useContext를 사용해 상태(state)와 상태 관리 함수 제공

// AuthProvider.jsx

import { createContext, useMemo, useReducer, useCallback, useContext } from 'react';
import authReducer, { INITIAL_AUTH_INFO, resetAuth, setAuth } from '@/stores/authStore';

// Context 생성
const AuthContext = createContext();

// Context의 Provider를 통해 상태 및 업데이트 함수를 제공하는 컴포넌트
export const AuthProvider = ({ children }) => {
  const [authState, dispatch] = useReducer(authReducer, INITIAL_AUTH_INFO, () =>
    localStorage.getItem('auth_info');
  );

  // 유저 정보 저장 함수
  const handleSetAuth = useCallback(
    (authInfo) => dispatch(setAuth(authInfo)),
    []
  );
  // 유저 정보 삭제 함수
  const handleResetAuth = useCallback(() => dispatch(resetAuth()), []);

  return (
    // value 속성을 통해 상태와 상태 업데이트 함수 제공
    <AuthContext.Provider
      value={{
        authInfo: useMemo(() => authState, [authState]),
        setAuth: handleSetAuth,
        resetAuth: handleResetAuth,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

AuthProvider로 App 감싸기

// App.tsx

import { AuthProvider } from '@/contexts/AuthProvider';
import router from '@/router';
import { RouterProvider } from 'react-router-dom';

function App() {
  return (
    <>
      <AuthProvider>
        <RouterProvider router={router} />
      </AuthProvider>
    </>
  );
}

export default App;

이렇게 하면, App의 모든 컴포넌트에서 아래의 코드 한 줄로 유저 정보를 조회, 저장(업데이트), 삭제할 수 있다.

const { authInfo, setAuth, resetAuth } = useContext(AuthContext);

라이브러리 의존도를 줄이고 싶다면 충분히 고려해볼 만한 방법인 것 같다!

profile
깊이 공부하는 웹개발자

0개의 댓글