본문 바로가기

Frontend/React

틱택톡 실습 with 공식문서

function Square(props) {
// 함수형 컴포넌트
  return (
    <button
      className="square"
      onClick={props.onClick}
      >
      {props.value}
    </button>
  );
}

// class Square extends React.Component {
//   constructor(props){
//     // 리액트에서 하위 클래스의 생성자를 정의할 때 super(props)
//     super(props);
//     // 리액트 컴포넌트는 this.state로 상태값을 갖음
//     this.state = {
//       value: null,
//     };
//   }
//   render() {
//     return (
//       <button 
//         className="square" 
//            // 화살표 함수 - this의 혼란스러운 동작을 피함
//         onClick={() => 
//           // this.setState({value: 'X'})
//           // 컴포넌트에서 setState를 호출하면 
//           // React는 자동으로 컴포넌트 내부의 자식 컴포넌트 역시 업데이트
          
//           this.props.onClick()
//         }>
//         {this.props.value}
//       </button>
//     );
//   }
// }

class Board extends React.Component {
  // 여러개의 자식으로부터 데이터를 모으거나 
  // 두 개의 자식 컴포넌트들이 서로 통신하게 하려면
  // 부모 컴포넌트에 공유 state를 정의해야 함.
  // 부모 컴포넌트는 props를 사용하여 자식 컴포넌트에 state를 다시 전달 할 수 있음!
  
  // class Game으로 이동
  // constructor(props) {
  //   super(props);
  //   this.state = {
  //     squares: Array(9).fill(null),
  //     xIsNext: true,
  //   }
  // }
  
  renderSquare(i) {
    return <Square 
             value={this.props.squares[i]}
             onClick={() => this.props.onClick(i)}             
           />;
  }

  render() {
    return (
      <div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}

class Game extends React.Component {
  constructor(props) {
    // 동작 기록
    super(props);
    this.state = {
      history: [{
        squares: Array(9).fill(null),
      }],
      stepNumber: 0,
      xIsNext: true
    };
  }
  
  handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    // .slice() 기존 배열을 수정하지 않고 squares 배열의 복사본을 생성, 수정
    // 데이터 불변성! - 복잡한 특징들을 단순화, 변화 감지, 다시 랜더링 되는 시기를 결정
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      history: history.concat([{
        squares: squares,
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }
  
  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: (step % 2) === 0,
    });
  }
  
  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);
    
    const moves = history.map((step, move) => {
      const desc = move ?
        'go to move #' + move :
        'go to game start';
      return (
        <li key={move}>
          <button onClick={() => this.jumpTo(move)}>
            {desc}
          </button>
        </li>
      );
    });
    
    let status;
    if (winner) {
      status = `Winner : ${winner}`;
    } else {
      status = `Next player: ${this.state.xIsNext ? 'X' : 'O'}`;
    }
    
    return (
      <div className="game">
        <div className="game-board">
          <Board 
            squares={current.squares}
            onClick={(i) => this.handleClick(i)}
          />
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
        </div>
      </div>
    );
  }
}

// ========================================

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Game />);

// 승자 확인
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;
}

https://ko.reactjs.org/tutorial/tutorial.html#completing-the-game

 

자습서: React 시작하기 – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

728x90

'Frontend > React' 카테고리의 다른 글

Next.js 배우기 시이이이작!  (0) 2022.05.21
Redux 복습하기 with 생활코딩 3  (0) 2022.05.13
Redux 복습 with 공식문서 2  (0) 2022.05.11
Redux 복습 with 공식문서 1  (0) 2022.05.11
React Life Cycle  (0) 2022.03.03