This commit is contained in:
haerong22
2021-03-12 15:11:10 +09:00
4 changed files with 89 additions and 23 deletions

View File

@@ -1,7 +1,8 @@
import React from "react"; import React, {memo} from "react";
import Tr from "./Tr"; import Tr from "./Tr";
const Table = ({ onClick, tableData, dispatch }) => { const Table = memo(({ tableData, dispatch }) => {
console.log("table rendered");
return ( return (
<table> <table>
{Array(tableData.length) {Array(tableData.length)
@@ -11,6 +12,6 @@ const Table = ({ onClick, tableData, dispatch }) => {
))} ))}
</table> </table>
); );
}; });
export default Table; export default Table;

View File

@@ -1,14 +1,24 @@
import React, { useCallback } from "react"; import React, { useCallback, useRef, useEffect, memo } from "react";
import { CLICK_CELL, CHANGE_TURN } from "./TicTacToe"; import { CLICK_CELL } from "./TicTacToe";
const Td = memo(({ rowIndex, cellIndex, dispatch, cellData }) => {
console.log("td rendered")
const ref = useRef([]);
useEffect(() => {
console.log(rowIndex === ref.current[0], cellIndex === ref.current[1], dispatch === ref.current[2], cellData === ref.current[3])
ref.current = [rowIndex, cellIndex, dispatch, cellData]
}, [rowIndex, cellIndex, dispatch, cellData])
const Td = ({ rowIndex, cellIndex, dispatch, cellData }) => {
const onClickTd = useCallback(() => { const onClickTd = useCallback(() => {
console.log(rowIndex, cellIndex); console.log(rowIndex, cellIndex);
if(cellData) {
return;
}
dispatch({ type: CLICK_CELL, row: rowIndex, cell: cellIndex }); dispatch({ type: CLICK_CELL, row: rowIndex, cell: cellIndex });
dispatch({ type: CHANGE_TURN }); }, [cellData]);
});
return <td onClick={onClickTd}>{cellData}</td>; return <td onClick={onClickTd}>{cellData}</td>;
}; });
export default Td; export default Td;

View File

@@ -1,4 +1,4 @@
import React, { useState, useReducer, useCallback } from "react"; import React, { useState, useEffect, useReducer, useCallback } from "react";
import Table from "./Table"; import Table from "./Table";
// 초기 state 값 설정 // 초기 state 값 설정
@@ -10,12 +10,14 @@ const initialState = {
["", "", ""], ["", "", ""],
["", "", ""], ["", "", ""],
], ],
recentCell: [-1, -1],
}; };
// action 이름 설정 - 하위 컴포넌트에서 사용하기 위해 모듈화 // action 이름 설정 - 하위 컴포넌트에서 사용하기 위해 모듈화
export const SET_WINNER = "SET_WINNER"; export const SET_WINNER = "SET_WINNER";
export const CLICK_CELL = "CLICK_CELL"; export const CLICK_CELL = "CLICK_CELL";
export const CHANGE_TURN = "CHANGE_TURN"; export const CHANGE_TURN = "CHANGE_TURN";
export const RESET_GAME = "RESET_GAME";
// reducer 설정 - dispatch 한 action 의 값들을 이용해 state 변경 // reducer 설정 - dispatch 한 action 의 값들을 이용해 state 변경
const reducer = (state, action) => { const reducer = (state, action) => {
@@ -34,6 +36,7 @@ const reducer = (state, action) => {
return { return {
...state, ...state,
tableData, tableData,
recentCell: [action.row, action.cell]
}; };
} }
// 칸을 클릭 할 때마다 O X 번갈아가면서 출력 // 칸을 클릭 할 때마다 O X 번갈아가면서 출력
@@ -43,17 +46,72 @@ const reducer = (state, action) => {
turn: state.turn === "O" ? "X" : "O", turn: state.turn === "O" ? "X" : "O",
}; };
} }
case RESET_GAME: {
return {
...state,
turn: "O",
tableData: [
["", "", ""],
["", "", ""],
["", "", ""],
],
recentCell: [-1, -1],
}
}
default:
return state;
} }
}; };
const TicTacToe = () => { const TicTacToe = () => {
// useReducer 사용 // useReducer 사용
const [state, dispatch] = useReducer(reducer, initialState); const [state, dispatch] = useReducer(reducer, initialState);
const { tableData, turn, winner, recentCell } = state;
// 승자 체크
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) { // 모든 칸이 다 차있으면 무승부
dispatch({type:RESET_GAME});
} else {
dispatch({ type: CHANGE_TURN });
}
}
}, [recentCell])
return ( return (
<> <>
<Table tableData={state.tableData} dispatch={dispatch} /> <Table tableData={tableData} dispatch={dispatch} />
{state.winner && <div>{state.winner}님의 승리</div>} {winner && <div>{winner}님의 승리</div>}
</> </>
); );
}; };

View File

@@ -1,23 +1,20 @@
import React from "react"; import React, {memo, useMemo} from "react";
import Td from "./Td"; import Td from "./Td";
const Tr = ({ rowData, rowIndex, dispatch }) => { const Tr = memo(({ rowData, rowIndex, dispatch }) => {
console.log("tr rendered")
return ( return (
<tr> <tr>
{Array(rowData.length) {Array(rowData.length)
.fill() .fill()
.map((td, i) => ( .map((td, i) => (
<Td useMemo(
rowIndex={rowIndex} () => <Td rowIndex={rowIndex} cellIndex={i} dispatch={dispatch} cellData={rowData[i]} >{""}</Td>,
cellIndex={i} [rowData[i]],
dispatch={dispatch} )
cellData={rowData[i]}
>
{""}
</Td>
))} ))}
</tr> </tr>
); );
}; });
export default Tr; export default Tr;