디스패치 / 액션 / 리듀서

useReducer를 사용하면 state를 변경해야할 때 dispatch함수를 호출하고, 액션 객체를 전달해서 state를 변경한다.

  • dispatch : 액션을 실행해주는 함수.
  • 액션 객체 : dispatch에 전달되는 객체로 리듀서가 실행해야할 로직을 알려주는 action.type과 리듀서가 변경해야할 state값을 가지고 있다.
  • reducer : 액션 객체를 해석해서 state를 직접 바꿔주는 함수. (리듀서는 dispatch가 실행될 때 마다 자동으로 호출된다.) --> reducer함수에서 반환하는 값은 새로운 state이다.

useReducer를 사용하면 state 변경 순서는 아래와 같아진다.

  1. 이벤트 발생
  2. dispatch 호출 (이벤트 객체를 만들어서 dispatch 함수 호출 시 이벤트 객체를 넘겨준다.)
  3. dispatch가 호출되면 자동으로 리듀서가 호출되면서 액션 객체를 해석하여 특정 로직 실행 (state변경)

 

reducer함수에서 주의해야할 점은 불변성을 꼭 지켜야한다는 것!

reducer함수에서 반환하는 값은 새로운 state인데 항상 새로운 객체를 만들어 바뀐 값만 바꿔줘야한다. 이를 위해 spread연산자를 활용해서 불변성을 지키자!

 

ACTION TYPE

  • 액션 타입은 리듀서함수에서 어떤 state를 수정할 로직을 실행해야할지 결정하는 중요한 정보이다.
  • 액션 타입은 상수로 따로 빼두는 것이좋다.
  • 액션 타입은 대문자로 하는 것이 커뮤니티 규칙이다.

 

 

TicTacToe.jsx

import React, {useCallback, useReducer, useState} from "react";
import Table from "./Table";

//state 초기값
const initialState = {
    winner : '',
    turn: 'O',
    tableData:[['','',''],['','',''],['','','']],
}
//액션 타입은 상수로 따로 빠두는것이 좋다.
//액션의 이름은 대문자로 하는것이 커뮤니티 규칙!
const SET_WINNER = 'SET_WINNER';

//리듀서 == 함수
const reducer = (state, action) => {
    //리듀서는 액션을 디스패치 할 때마다 실행된다.
    switch(action.type){
        case SET_WINNER:
            //state.winner = action.winner; 이렇게 하면 안된다!!!!
            //우리는 항상 새로운 객체를 만들어서 바뀐 값만 바꿔줘야한다. 불변성 지켜!.
            return {
                ...state,
                winner: action.winner,
            }

    }
}

const TicTacToe = () => {
    /*
    const [winner, setWinner] = useState('');
    const [turn, setTurn] = useState('O');
    const [tableData, setTableData] = useState([['','',''],['','',''],['','','']]);
    */
    const [state, dispatch] = useReducer(reducer, initialState);

    //컴포넌트에 있는 함수들은 다 useCallback으로 감싸주자.
    const onClickTable = useCallback(()=>{
        //dispatch는 액션을 실행해주는 함수이다. dispatch에 전달되는 값은 액션객체이다.
        //액션 객체를 해석해서 state를 직접 바꿔주는 역할을 하는 것이 리듀서이다.
        dispatch({type:SET_WINNER, winner:'O'});
    },[]);

    return(
        <>
            <Table onClick={onClickTable} tableData={state.tableData}/>
            {
                state.winner && <div>{state.winner}님의 승리</div>
            }
        </>
    );
}

export default TicTacToe;

 

Table.jsx

import React from 'react';
import Tr from "./Tr";

const Table = ({onClick, tableData}) => {
    return (
        <table onClick={onClick}>
            {Array(tableData.length).fill().map((tr,i)=><Tr rowData={tableData[i]}/>)}
        </table>
    );
};

export default Table;

 

Tr.jsx

import React from 'react';
import Td from "./Td";

const Tr = ({rowData}) => {
    return (
        <tr>
            {
                Array(rowData.length).fill().map((td)=><Td/>)
            }
        </tr>
    );
};

export default Tr;

 

+ Recent posts