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 |