React Context API는 React에 내장된 상태 관리 솔루션
이다.
Redux는 외부 라이브러리로, Context API와 유사한 역할을 하는 상태 관리 솔루션이다.
Redux를 이해하기 위해 먼저 Reducer
가 뭔지 알아보아야 한다.
Reducer는 상태 관리를 위한 패턴
이다.
단순한 경우에는 Reducer를 Context와 함께 쓰는 것보다 Context만 사용하는게 더 간단하지만, 관리해야 할 데이터가 복잡한 경우 Reducer를 사용하는게 더 좋다.
(Reducer 사용방식이 복잡해서 처음에 이해하기 좀 어렵다..)
ex.
장바구니의 아이템과 개별 수량, 전체 수량 정보를 관리하는 Cart Context
가 있을 때, 각각의 상태는 각각의 useState를 통해 관리된다.
context 방식과 매우 유사한 방식으로 상태를 관리하지만, 보다 직관적이고 useState를 사용하지 않는다는 차이점이 있다.
Reducer는 Action
을 활용해 어떤 동작을 수행할지 지시한다.
Action은 객체이며 두가지 key로 구성되어 있는데, type
과 payload
이다.
import { createContext, useEffect, useReducer } from "react";
import {
onAuthStateChangedListener,
createUserDocumentFromAuth,
} from "../firebase/firebase.utills";
export const UserContext = createContext({
setCurrentUser: () => null,
currentUser: null,
});
export const UserProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
const value = { currentUser, setCurrentUser };
useEffect(() => {
const unsubscribe = onAuthStateChangedListener((user) => {
if (user) {
createUserDocumentFromAuth(user);
}
setCurrentUser(user);
});
return unsubscribe;
}, []);
return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
};
- useReducer import 하기
- INITIAL_STATE 세팅하기
- USER_ACTION_TYPES 담아두기
(오타 방지를 위해 객체에 따로 담아서 보관)- Reducer 함수 만들기
switch를 이용해 케이스별로 어떤 동작을 시행할지 지정한다.
default 동작은 error throw하기.- useReducer로 Reducer 함수와 INITIAL_STATE 가져오기.
dispatch로 action 일으키기
import { createContext, useState, useEffect, useReducer } from "react";
import {
onAuthStateChangedListener,
createUserDocumentFromAuth,
} from "../firebase/firebase.utills";
export const UserContext = createContext({
setCurrentUser: () => null,
currentUser: null,
});
export const USER_ACTION_TYPES = {
SET_CURRENT_USER: "SET_CURRENT_USER ",
};
const INITIAL_STATE = {
currentUser: null,
};
const userReducer = (state, action) => {
const { type, payload } = action;
switch (type) {
case USER_ACTION_TYPES.SET_CURRENT_USER:
return { ...state, currentUser: payload };
default:
throw new Error(`Unhandled type ${type} in userReducer`);
}
};
export const UserProvider = ({ children }) => {
const [{ currentUser }, dispatch] = useReducer(userReducer, INITIAL_STATE);
const SetCurrentUser = (user) =>
dispatch({ type: USER_ACTION_TYPES.SET_CURRENT_USER, currentUser: user });
useEffect(() => {
const unsubscribe = onAuthStateChangedListener((user) => {
if (user) {
createUserDocumentFromAuth(user);
}
SetCurrentUser(user);
});
return unsubscribe;
}, []);
const value = { currentUser };
return <UserContext.Provider value={value}>{children}</UserContext.Provider>;
};