useState와 비슷합니다 상태관리를 할 수 있어요
useState가 더 적은 코드를 작성하지만
많은 이벤트 핸들러를 통해 값을 수정하는 경우 코드를 줄이는데 useReducer가 적합할 수 있어요
useState는 상태 업데이트가 단순할 때 가독성이 좋지만 복잡해지면 어려울 수도 있어요
useReducer는 발생한 이벤트와 해당하는 로직을 명확하게 구분이 가능해요
예제는 todo State관리를 해보겠습니다
우선 Context를 만들기 위해 CreateContext를 이용하여 만들어 줍니다
const TodoStateContext = createContext(null)
const TodoDispatchContext = createContext(null)
State값을 관리할 Context와 dispatch함수를 관리할 Context 해서 두개의 ConText를 생성해줍니다
useReducer에서 사용할 reducer를 만들어주겠습니다
todo = {
id:number,
content:string,
isComplete:boolean
}
function reducer((state,action)){
switch(action.type){
case 'ADD_TODO':
state.push(action.todo);
break;
case 'DELETE_TODO':
return state.filter(prev => prev.id !== action.todo.id)
default:
throw new Error('Unhandle Action')
}
}
간단하게 todo추가와 삭제만 설정해두었습니다
이제 Context.Provider로 감싼 컴포넌트를 만들어볼께요
function TodoProdiver({children}){
const [state,dispatch] = useReducer(reducer,[])
return (
<TodoStateContext.Provider value={state}> //value: 공유할 값을 넣어준다
<TodoDispatchContext.Provider value={dispatch}>
{children}
</TodoDispatchContext.Provider>
</TodoStateContext.Provider>
)
}
export default TodoProvider
export function useTodoState(){
const state = useContext(TodoStateContext)
if(!state) throw new Error('cannot find Provider')
return state
}
export function useTodoDispatch(){
const dispatch = useContext(TodoDispatchContext)
if(!dispatch) throw new Error('cannot find Provider')
return dispatch
}
먼저 TodoProvider를 보시면
useReducer를 사용하여 아까 만들어 두었던 reducer를 추가해주고,초기값은 []로 설정해주었습니다
return에는 만들어 두었던 Context.Provider로 children감싸서 반환해줍니다
useTodoState,useTodoDispatch를 통해 쉽게 state값과 dispatch함수를 가져올 수 있도록 만들어 두었습니다
우선 Provier를 적용시켜줘야합니다 최상단 파일에서 만들어 두었던 TodoProvider를 감싸주시면 됩니다
예로 App.jsx에 감싸보겠습니다
import React from 'react';
import Router from '../src/router';
import TodoProvider from '../src/component'
function App() {
return (
<TodoProvider>
<Router/>
</TodoProvider>
);
}
export default App;
function TodoPage(){
const todoState = useTodoState()
const dispatch = useTodoDispatch()
const handleAddTodo = (todo) =>{
dispatch({
type:'ADD_TODO',
todo:{
id,
content,
isComplete
}
})
}
const handleDeleteTodo = (id) => {
dispatch({
type:'DELETE_TODO',
todo:{
id,
content,
isComplete
}
})
}
return(
{todostate.map(todo => (
<div>
{todo.content}<button onClick={handleDeleteTodo}>삭제</button>
</div>))}
)
}
이벤트마다 함수를 정의하고 dispatch에 type과 필요한 data를 넘겨주어 useReducer를 통해 state값을 변경할 수 있습니다