리액트에서 자체적으로 제공하는 훅중에 하나입니다. 사실 전역 상태 관리보다는 상태관리에 조금 더 관련이 있습니다.
하지만 이 useReducer는 context API와 리덕스와 함께 사용을 하는 경우가 많기 때문에 개념을 잘 다져놓는 것이 좋습니다.
const [state, dispatch] = useReducer(reducer, initialArg, init);
state
와 dispatch
를 반환합니다.(state, action) => newState
의 형태로 받습니다.예시
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
프로젝트의 크기가 커지다보면 setState를 하기 전에 현재의 state를 조작하는 길이가 길어질 수 있습니다. 이렇게 복잡한 state를 다룰 때 userReducer를 이용해 컴포넌트의 상태와 컴포넌트의 상태를 변화하는 로직을 나눠 다룰 수 있습니다.
또한 state가 이전 state에 의존적인 경우에는 useState보다 useReducer를 선호합니다.
useState의 setState의 경우 비동기로 처리가 되기 때문에 같은 state를 여러번 호출했을 때 state가 병합되어 업데이트가 될 수도 있습니다. 이런 이슈가 useReducer에서는 발생하지 않기 때문에 useState보다 useReducer를 선호합니다.
리액트 공식문서에서 보다 자세한 내용 및 예시를 확인할 수 있습니다.
다음은 지난 번 useContext를 공부하며 만든 예시입니다.
import React, { createContext, useState } from "react";
export const UserContext = createContext();
export default function UserStore(props) {
const [job, setJob] = useState("FE-developer");
const user = {
name: "0seo",
job,
changejob: (upatedJob) => setJob(upatedJob),
};
return (
<UserContext.Provider value={user}>{props.children}</UserContext.Provider>
);
}
현재 예시의 경우 user에 다루는 정보가 많지 않기 떄문에 const [job, setJob] = useState("FE-developer");
, const [name, setName] = useState("0seo");
과 같이 각각의 상태값을 만들어 사용을 할 수 있지만 프로젝트의 규모가 커지다보면 한계가 있게 됩니다.
이런 경우 useState가 아닌 useReducer를 이용해 관리를 할 수 있습니다.
import React, { createContext, useState, useReducer } from "react";
export const UserContext = createContext();
const initialUser = {
name: "0seo",
jog: "FE-developer",
};
const userReducer = (state, action) => {
switch (action.type) {
case "changeJob":
return { ...state, job: action.text };
break;
default:
break;
}
};
export default function UserStore(props) {
const [user, dispatch] = useReducer(userReducer, initialUser);
return (
<UserContext.Provider value={dispatch}>
{props.children}
</UserContext.Provider>
);
}
BlogPage.js
import React, { useContext } from "react";
import { UserContext } from "../store/user";
export default function BlogPage() {
const dispatch = useContext(UserContext);
console.log(dispatch);
return (
<div>
<h1>BlogPage</h1>
<button
onClick={() => dispatch({ type: "changeJob", text: "BE-developer" })}
>
Change Job
</button>
</div>
);
}
버튼을 누르면 user의 job이 바뀐 것을 확인할 수 있습니다.