개발공부일지
React - Tutorial : Tic-Tac-Toe 본문
목차
1. 리액트 튜토리얼 따라하기
2. Lifting state up
3. immutability (불변성)
4. Winner 설정
5. Time Travel
6. Picking a Key
7. 완성코드
1. 리액트 튜토리얼 따라하기
https://react.dev/learn/tutorial-tic-tac-toe
https://codesandbox.io/p/sandbox/exciting-rubin-5clxn7?file=%2FApp.js%3A1%2C1-151%2C1
2. Lifting state up
export default function Board() {
const [squares, setSquares] = useState(Array(9).fill(null));
function handleClick(i) {
const nextSquares = squares.slice();
nextSquares[i] = 'X';
setSquares(nextSquares);
}
}
3. immutability (불변성)
const squares = [null, null, null, null, null, null, null, null, null];
const nextSquares = ['X', null, null, null, null, null, null, null, null];
// Now `squares` is unchanged, but `nextSquares` first element is 'X' rather than `null`
- 배열을 변경하지않고 데이터를 변경하는 경우
4. Winner 설정
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
5. Time Travel
- 배열을 slice로 새 복사본을 만들어서 사용하여 squares의 이전 버전을 history에 저장
- 눌렀던 동작에 대해서 history에 map()를 사용하여 과거동작 위치 보여주기
const moves = history.map((squares, move) => {
let description;
if (move > 0) {
description = 'Go to move #' + move;
} else {
description = 'Go to game start';
}
return (
<li>
<button onClick={() => jumpTo(move)}>{description}</button>
</li>
);
});
6. Picking a Key
- 동적 목록을 작성할때마다 적절한 키를 할당하는것이 좋다고한다!
- 전역적으로 고유할 필요는 없지만 구성 요소와 해당 형제 사이에서 고유하면 된다고한다!!
<li key={move}>
<button onClick={() => jumpTo(move)}>{description}</button>
</li>
7. 완성코드
import { useState } from "react";
function Square({ value, onSquareClick }) {
return (
<button className="square" onClick={onSquareClick}>
{value}
</button>
);
}
function Board({ xIsNext, squares, onPlay }) {
function handleClick(i) {
if (calculateWinner(squares) || squares[i]) {
return;
}
const nextSquares = squares.slice();
if (xIsNext) {
nextSquares[i] = "X";
} else {
nextSquares[i] = "O";
}
onPlay(nextSquares);
}
const winner = calculateWinner(squares);
let status;
if (winner) {
status = "Winner: " + winner;
} else {
status = "Next player: " + (xIsNext ? "X" : "O");
}
return (
<>
<div className="status">{status}</div>
<div className="board-row">
<Square
value={squares[0]}
onSquareClick={() => handleClick(0)}
/>
<Square
value={squares[1]}
onSquareClick={() => handleClick(1)}
/>
<Square
value={squares[2]}
onSquareClick={() => handleClick(2)}
/>
</div>
<div className="board-row">
<Square
value={squares[3]}
onSquareClick={() => handleClick(3)}
/>
<Square
value={squares[4]}
onSquareClick={() => handleClick(4)}
/>
<Square
value={squares[5]}
onSquareClick={() => handleClick(5)}
/>
</div>
<div className="board-row">
<Square
value={squares[6]}
onSquareClick={() => handleClick(6)}
/>
<Square
value={squares[7]}
onSquareClick={() => handleClick(7)}
/>
<Square
value={squares[8]}
onSquareClick={() => handleClick(8)}
/>
</div>
</>
);
}
export default function Game() {
const [history, setHistory] = useState([Array(9).fill(null)]);
const [currentMove, setCurrentMove] = useState(0);
const xIsNext = currentMove % 2 === 0;
const currentSquares = history[currentMove];
function handlePlay(nextSquares) {
const nextHistory = [...history.slice(0, currentMove + 1), nextSquares];
setHistory(nextHistory);
setCurrentMove(nextHistory.length - 1);
}
function jumpTo(nextMove) {
setCurrentMove(nextMove);
}
const moves = history.map((squares, move) => {
let description;
if (move > 0) {
description = "Go to move #" + move;
} else {
description = "Go to game start";
}
return (
<li key={move}>
<button onClick={() => jumpTo(move)}>{description}</button>
</li>
);
});
return (
<div className="game">
<div className="game-board">
<Board
xIsNext={xIsNext}
squares={currentSquares}
onPlay={handlePlay}
/>
</div>
<div className="game-info">
<ol>{moves}</ol>
</div>
</div>
);
}
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (
squares[a] &&
squares[a] === squares[b] &&
squares[a] === squares[c]
) {
return squares[a];
}
}
return null;
}
※ CodeSendbox 처음써보는 툴이라.. import도 console탭도 React DevTools도 모르겠다..
- npx해서 로컬에서도 해봐야겠다!
- 코드 익숙해지면 CSS도 수정해야겠다!
※ 2번째는 local에서 작성
※ 3번째는 atomic 디자인 패턴으로 나눠서 작성
/src
/ -- /components
/ -- -- /atoms
/ -- -- -- Square.jsx
/ -- -- /molecules
/ -- -- -- Board.jsx
/ -- -- /oranisms
/ -- -- -- Game.jsx
/ -- /styles
/ -- -- style.css
/ -- /utils
/ -- -- CalculateWinner.jsx
/ -- App.css
/ -- App.js
/ -- index.css
/ -- index.js
'React' 카테고리의 다른 글
React - learn - Passing Props to a Component (컴포넌트에 props 전달하기) (0) | 2023.11.28 |
---|---|
React - react router dom (1) | 2023.11.27 |
React - class component, function component (0) | 2023.11.24 |
React - babel, webpack, react 설치, npm ERR! (1) | 2023.11.23 |
React - 리액트, 특징, component, JSX (0) | 2023.11.22 |