useState 말고도 useReducer로 상태를 관리해줄 수가 있다. 컴포넌트에 종속된 useState와는 달리 상태 관련 로직을 컴포넌트에서 분리시킬 수도 있고 컴포넌트 바깥에 작성해 줄수도 있으며 다른 파일에 작성한 후 불러와서 사용하는 것도 가능하다.
리덕스(Redux)의 핵심부분인 reducer를 거의 그대로 구현한다.
소규모 앱에서 useReducer와 컨텍스트 API 조합으로 리덕스를 대체하는 것이 가능하다.
기존의 Hooks는 state마다 setState를 해줘야 했지만 useReducer를 쓰면 한 번의 작업으로 모든 state를 설정해줄 수 있다.
const [state, dispatch] = useReducer(reducer, initalState)
state
에는 reducer
에서 설정한 state가 들어간다.
클래스처럼 state.{속성}
으로 접근할 수 있다.
(리덕스에서도 쓰이는) 액션 객체가 들어간다. reducer로 보내줄 값들을 객체 형태로 보내준다.
dispatch({type : 'SET_WINNER', state : '0'}, [])
{type : 'SET_WINNER', state : '0'}
객체가 action 객체가 된다.dispatch
할 수 있다.액션 객체만으로는 state를 바꿀 수 없다. 액션을 해석해서 state를 직접 바꾸는 역할을 하는 것이 reducer이다.
💡 액션의 이름은 상수로 빼는 편이 좋다.state가 있고, 액션을 dispatch해서 state를 바꾸는데, 그것을 어떻게 바꿀지는 reducer에 써준다.
dispatch만 자식 컴포넌트에서 props로 받아 action을 보내도 reducer가 작동된다.
현재 상태, 액션 객체를 파라미터로 받아와서 새로운 상태로 반환해주는 함수이다.
const reducer = (state, action) => {
switch(action.type)
case 'SET_WINNER' :
// state.winner = action.winner; 안돼!
return {
...state,
winner: action.winner
}
액션 객체를 구분해서 실제로 실행하는 역할을 한다.
dispatch
를 통한 액션 객체가 reducer의 action 인자로 들어온다. state에는 기존의 state가 들어온다.
action 객체의 type을 switch에 집어넣어서 해당되는 case가 있다면 state를 수정한다.
state에 접근해서 직접 바꾸면 안 된다. 객체는 같은 주소를 가리키고 있기에 리액트는 객체 내부의 값이 변했다고 한들 변했다고 생각하지 않고 리렌더링을 하지 않게 된다. 기존 state의 값과 수정된 값을 가진 새로운 객체를 만들어 리턴하는 방식으로 바꿔야만 한다.
state의 초기값을 설정한다. 클래스의 state와 동일한 모습. 객체형식으로 선언하는 것이 일반적이다.
// TicTacToe.jsx
import React, {useRef, useState, useReducer, useCallback} from 'react';
import Table from './Table'
const initalState = {
winner : "",
turn : "0",
tableData : [['','',''],['','',''],['','','']],
};
const SET_WINNER = "SET_WINNER";
const reducer = (state, action) => {
switch(action.type){
case SET_WINNER :
return {
...state,
winner: action.winner
}
}
}
const TicTacToe = () => {
const [state, dispatch] = useReducer(reducer, initalState);
const onClickTable = useCallback(() => {
dispatch({type : SET_WINNER, winner : 'O'});
}, []);
return (
<>
<Table onClick={onClickTable} tableData={state.tableData}/>
{state.winner && <div>{state.winner}님의 승리</div>}
</>
)
}
export default TicTacToe;
전역적으로 state를 관리하고 싶은 곳에 useReducer를 사용. 분할 할당 받은 state
로는 state를 관리,dispatch
로 action 보내서 state를 변경.
dispatch
만 자식 컴포넌트에 props로 보내주어도 reducer
함수에 action이 잘 전달된다.