Notice
Recent Posts
Recent Comments
Link
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

개발공부일지

React - Tutorial : Tic-Tac-Toe 본문

React

React - Tutorial : Tic-Tac-Toe

보람- 2023. 11. 24. 17:58

목차

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