본문 바로가기
FE - Tools/React

[React] Context API와 useReducer 사용법 알아보기

by thedev 2023. 5. 11.

 

Context API와 useReducer로 상태관리하기

 


 

# Redux 대신 Context API

 

 로그인 기능을 구현하고 나면, 사용자의 정보를 변수에 담아 전역적으로 사용해야 한다. 그래서 Redux를 사용할까 하다가... 이 프로젝트는 전역적으로 관리해야할 정보가 사용자 정보 딱 하나밖에 없는데 Redux까지 사용할 필요가 있을까? 라는 생각이 들었다. 그래서 Redux 대신, React에서 제공하는 Context API를 사용해보기로 했다.

 

 사용 방법은 간단하다. Context를 생성할 컴포넌트를 하나 만들고, creactContext와 useContext를 사용해주면 된다.

 

// AuthContext.tsx

import { createContext, useContext, useEffect, useReducer } from "react";

const AuthContext = createContext({});
export const useAuth = () => useContext(AuthContext);

export default function AuthContextProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const initialState: State = {
    email: null,
    name: null,
    photo: null,
  };

  const [user, setUser] = useState();
  
  useEffect(() => {
    const authState = onAuthStateChanged(auth, (user) => {
      if (user) {
        setUser({
          email: user.email,
          name: user.displayName,
          photo: user.photoURL,
      }
    });
    return () => authState();
  }, []);

  return (
    <AuthContext.Provider value={{ user }}>
      {children}
    </AuthContext.Provider>
  );
}

 

그리고 user 정보를 사용하고 싶은 컴포넌트로 가서 다음과 같이 import하고 사용하면 된다.

 

import { useAuth } from "./components/AuthContext";

const { user } = useAuth();

 

 

# 문제 상황

 

 그러나 이렇게 user 정보를 관리하니, 사용자의 정보가 바로 업데이트가 되지 않는다는 문제가 생겼다. 예를 들어 사용자의 이름을 바꾸면 바뀐 이름이 바로 화면에 표시되어야 하는데, 새로고침을 해야만 바뀐 이름이 적용되었다. 그리고 그 문제는 바로... useState 때문이었다. useState는 비동기적으로 실행되기 때문이다... (React로 개발하면서 이거 때문에 힘들었던 적이 한두번이 아님...😢)

 

 만약 Redux로 사용자 상태를 관리했다면 이런 문제가 발생하지 않았을 텐데, useContext를 사용하고 그 내부에서 useState로 사용자 정보를 저장했기에 어쩔 수가 없었다. 이 문제를 어떻게 해결해야 할까... 고민하던 차에 말로만 듣던useReducer를 사용해보기로 했다. useReducer는 React에서 제공하는 Hook인데, useState와 비슷한 기능을 한다. 그러나, 변경된 내용이 바로 적용된다!

 

// AuthContext.tsx

import { createContext, useContext, useEffect, useReducer } from "react";

const AuthContext = createContext({});
export const useAuth = () => useContext(AuthContext);

export default function AuthContextProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const initialState: State = {
    email: null,
    name: null,
    photo: null,
  };

  const reducer = (user: State, action: Action): State => {
    if (action.type === "Update") {
      return {
        email: action.payload.email,
        name: action.payload.name,
        photo: action.payload.photo,
      };
    }
    return user;
  };
  const [user, dispatch] = useReducer(reducer, initialState);

  useEffect(() => {
    const authState = onAuthStateChanged(auth, (user) => {
      if (user) {
        dispatch({
          type: "Update",
          payload: {
            email: user.email,
            name: user.displayName,
            photo: user.photoURL,
          },
        });
      }
    });
    return () => authState();
  }, []);

  return (
    <AuthContext.Provider value={{ user }}>
      {children}
    </AuthContext.Provider>
  );
}

 

  useState로 작성된 코드를 useReducer로 변경하였다. Reducer로 변수를 관리하니 새로고침 없이도 변경사항이 바로 적용이 되었다. 👏👏👏

 


 

참고자료

https://youtu.be/ZmpO65DhRN0