상태 관리 라이브러리에는 Vuex, Redux, MobX
등이 있다. 대규모 어플리케이션을 개발하면서 많고 흩어져있는 데이터를 한 곳에 모아 관리하기 위해 쓰인다.
React
도 역시 state
가 많아질 수록 관리가 어려워지고, 복잡한 애플리케이션의 경우 컴포넌트로 Props
를 이용해 데이터를 전달해주기에는 많은 컴포넌트 경로를 거쳐가야 할 수도 있다. 따라서 Redux
를 많이 쓰긴하지만, useReducer
와 Context API
를 사용하여 어느 정도 커버는 할 수 있다고 한다👍
useReducer는 useState보다 더 다양한 컴포넌트 상황에 따라 다양한 상태를 다른 값으로 업데이트해 주고 싶을 때 사용하는 Hook이다. state의 개수를 대폭 줄일 수 있다.
현재 상태, 액션 객체를 매개변수로 받아와서 새로운 상태를 반환해주는 함수
import React, { useState, useReducer } from 'react';
import Table from './Table';
function App() {
const [winner, setWinner] = useState('');
const [turn, setTurn] = useState('0');
const [tableData, setTableData] = useState('');
return(
<Fragment>
<Table />
{winner && <div>{winner}님의 승리</div>}
</Fragment>
)
}
useState
를 이용하여 여러 state를 각각 관리하고 있으며, winner state를 컴포넌트에 렌더링하고 있다.
useReducer를 사용한 코드
위의 코드를 useReducer
를 이용한 코드로 바꿔보자.
import React, { useState, useReducer, useCallback } from 'react';
import Table from './Table';
const initialState = {
winner:'',
turn:"0",
tableData:'',
}
const SET_WINNER = 'SET_WINNER'; // 상수 처리
const reducer = (state, action) => {
switch(action.type) {
case SET_WINNER:
return {
...state, // 기존의 state를 복사 (spread 문법)
winner : action.winner // 바뀌는 데이터만 덮어써주기
}
}
}
function App() {
const [state, dispatch] = useReducer(reducer, initialState);
const onClickTable = useCallback(()=> {
dispatch({ type:'SET_WINNER' }, winner : '0');
}, [])
return(
<Fragment>
<Table onClick = {onClickTable}/>
{state.winner && <div>{state.winner}님의 승리</div>}
</Fragment>
)
}
initialState
는 이전에 만들었던 state를 묶어두면 된다. 관리하고 싶은 state를 묶어서 선언한다고 생각하자.
/* initialState */
const initialState = {
winner:'',
turn:"0",
tableData:'',
}
그리고 useReducer
를 사용하는 부분이다.
const [state, dispatch] = useReducer(reducer, initialState);
useCallback()
을 사용하여 클릭이벤트핸들러 함수를 구현한다.
const onClickTable = useCallback(()=> {
dispatch({ type:'SET_WINNER' ,winner : '0' });
}, [])
dispatch
안에 들어가는 것은 action
이라고 부른다. 따라서 액션객체를 위와 같이 만들어줘야하며, type
데이터가 있어야 한다.
dispatch한다는 것은 action을 실행하는 것과 일맥상통한다.
reducer
는 함수이므로 Arrow Function의 형태로 선언하였다. reducer
는 함수라는 것을 꼭 기억하자. action
만있다고해서 자동으로 state가 바뀌는 것이 아니다. action
을 해석해서 state를 직접 바꿔주는 역할을 하는 것이 reducer
다. action
을 dispatch
할 때 마다 reducer
가 실행되며, reducer
함수는 switch
문을 이용하여 아래와 같이 구현한다.
/* reducer */
const reducer = (state, action) => {
switch(action.type) {
case SET_WINNER:
return {
...state, // 기존의 state를 복사 (spread 문법)
winner : action.winner // 바뀌는 데이터만 덮어써주기
}
}
}
action의 이름은 const상수로 빼서 대문자로 사용하는 것을 추천한다.
const SET_WINNER = 'SET_WINNER'; // 상수 처리
useReducer를 사용했을 때의 가장 큰 장점은 컴포넌트 업데이트 로직을 컴포넌트 바깥으로 빼낼 수 있다는 것
따라서 context API를 사용하여 로직을 구현할 때 useReducer가 같이 많이 사용된다.