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로 변수를 관리하니 새로고침 없이도 변경사항이 바로 적용이 되었다. 👏👏👏
참고자료
'FE - Tools > React' 카테고리의 다른 글
[React] 제어 컴포넌트와 비제어 컴포넌트를 적절하게 사용하는 법 (0) | 2023.03.12 |
---|---|
[React] Express로 CORS 에러 해결하기 (0) | 2023.03.01 |
[React] React에서 네이버 지도 API 사용하기 (0) | 2023.01.19 |
[React] useParams 이용하기 (0) | 2022.12.22 |
[React] useEffect와 useLayoutEffect의 차이 (0) | 2022.12.20 |