본문 바로가기
패스트캠퍼스/자습

리액트 51~55강 정리

by sunnykim91 2019. 10. 3.

useReducer

state들을 한번에 관리하기 어렵기 때문에 사용

 

dispatch 안에는 액션이 들어감.

 

비동기 안에서 state를 변경하려면 useEffect를 사용한다

 

dispatch가 안에 있는 액션을 하는 것은 비동기이다.  setState역할을 함

 

memo를 적용했는데도 리랜더링이 발생할때 useMemo를 사용하여 component자체를 기억해버리는 방법도 있다.

 

//tictactoe.jsx

import React, {useEffect ,useReducer , useCallback} from 'react';
import Table from './Table';

const initalState = {
  winner: '',
  turn: 'O',
  tableData: [
    ['', '', ''],
    ['', '', ''],
    ['', '', '']
  ],
  recentCell: [-1, -1],
};

export const SET_WINNER = 'SET_WINNER';
export const CLICK_CELL = 'CLICK_CELL';
export const CHANGE_TURN = 'CHANGE_TURN';
export const RESET_GAME = 'RESET_GAME';

const reducer = (state, action) =>{
  switch (action.type) {     
    case SET_WINNER:
      // state.winner = action.winner;  이렇게 직접 바꾸면 안됨.
      return {
        ...state,               // 기존 state들을 바꾸는게 아니라 새로운 state에 바꾸는 부분만 바꿔서 넣는거
        winner: action.winner,
      };
      case CLICK_CELL: {
        const tableData = [...state.tableData];
        tableData[action.row] = [...tableData[action.row]];   // immer라는 라이브러리로 가독성 해결
        tableData[action.row][action.cell] = state.turn;
        return {
          ...state,
          tableData,
          recentCell: [action.row, action.cell],
        };
      }
      case CHANGE_TURN: {
        return {
          ...state,
          turn: state.turn === 'O' ? 'X' : 'O',
        };
      }
      case RESET_GAME: {
        return {
          ...state,
          turn: 'O',
          tableData: [
            ['', '', ''],
            ['', '', ''],
            ['', '', ''],
          ],
          recentCell: [-1, -1],
        }
      }
  }
};

const TicTacToe = () => {
  const [state, dispatch] = useReducer(reducer, initalState);
  const { tableData, turn, winner, recentCell } = state;

  // const [winner, setWinnner] = useState('');
  // const [turn, setTurn] = useState('O');
  // const [table, setTable] = useState([['','',''],['','',''],['','','']]);

  const onClickTable = useCallback( () => {
    dispatch({ type: 'SET_WINNER', sinner: 'O' });
  }, []);

useEffect(() => {
  const [row, cell] = recentCell;
  if(row<0){
    return;
  }
  
  let win = false;

  if (tableData[row][0] === turn && tableData[row][1] === turn && tableData[row][2] === turn ){
    win = true;
  }
  if (tableData[0][cell] === turn && tableData[1][cell] === turn && tableData[2][cell] === turn ){
    win = true;
  }
  if (tableData[0][0] === turn && tableData[1][1] === turn && tableData[2][2] === turn ){
    win = true;
  }
  if (tableData[0][2] === turn && tableData[1][1] === turn && tableData[2][0] === turn ){
    win = true;
  }

  if(win) { // 승리시
    dispatch({ type: SET_WINNER, winner: turn});
    dispatch({ type: RESET_GAME })
  } else {
    //무승부 검사
    let all = true; // all이 true면 무승부라는 뜻
    tableData.forEach( (row) => {
      row.forEach( (cell) => {
        if (!cell) {
          all = false;
        }
      });
    });
    if (all) {

    } else {
      dispatch({ type: CHANGE_TURN});
    }
  };

}, [recentCell]);

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

export default TicTacToe;

 

//tr.jsx

import React, { useRef, useEffect, memo } from 'react';
import Td from './Td';

const Tr = memo(({rowData, rowIndex, dispatch}) => {

    const ref = useRef([]);
    useEffect(() => {
        ref.current = [rowData, dispatch, rowIndex];
    }, [rowData, dispatch, rowIndex]);

    return (
        <tr>
            {Array(rowData.length).fill().map((td, i) => ( 
                <Td key={i} dispatch={dispatch} rowIndex={rowIndex} cellIndex={i} cellData={rowData[i]} >{''}</Td>
            ))}
        </tr>
    );
});

export default Tr;

 

 

//Td.jsx


import React, { useCallback, useEffect, useRef, memo } from 'react';
import { CLICK_CELL } from './tictactoe';

const Td = memo( ({ rowIndex, cellIndex, dispatch, cellData}) => {

    const ref = useRef([]);
    useEffect(()=> {
        ref.current = [rowIndex, cellIndex, dispatch, cellData];
    }, [rowIndex, cellIndex, dispatch, cellData]);

    const onClickTd = useCallback( () => {
        console.log(rowIndex, cellIndex);
        if(cellData) {
            return;
        }
        dispatch({ type: CLICK_CELL, row: rowIndex, cell: cellIndex });
    }, [cellData]);

    return (
        <td onClick={onClickTd}>{cellData}</td>
    )
});

export default Td;

 

 

 

//Table.jsx

import React, { memo } from 'react';
import Tr from './Tr';

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

export default Table;
반응형

'패스트캠퍼스 > 자습' 카테고리의 다른 글

리액트 61~69강 정리  (0) 2019.10.09
poiemaweb 23강 복습( 클로저)  (0) 2019.10.04
poiemaweb 20~21강 복습  (0) 2019.10.01
리액트 46~50강 정리  (0) 2019.10.01
poiemaweb 18~19강 복습  (0) 2019.09.30