아래 내용은 facebook에서 제공하는 Tutorial을 번역한 것입니다. 오욕이 있거나 잘못된 부분이 있으면 말씀해 주시기 바랍니다


출처 : https://facebook.github.io/react/tutorial/tutorial.html



Tutorial: Intro To React



What We're Building


오늘, 우리는 대화 tic-tac-toe 게임을 만들 것입니다. 일단 여기서는 HTML JavaScript 익숙하다고 가정하겠지만, 이전에 사용하지 않았더라도 쉽게 따라 있습니다.

 

최종 결과물을 먼저 확인하고 싶다면 "최종 결과"를 클릭해서 확인할 있습니다 : 최종 결과. 게임을  해보십시오. 이동 목록에 있는 링크를 클릭하여 이전에 이동했던 시간으로 이동할 고, 이동 후에는 board 어떻게 보여지는지 확인 있습니다.


 

React ?


React는 사용자 인터페이스를 구축하기위한 선언적이고 효율적이며 유연한 JavaScript 라이브러리입니다


React에는 여러 종류의 Component가 있지만, 일단 우리는 React.Component 서브 클래스로 시작하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ShoppingList extends React.Component {
  render() {
    return (
      <div className="shopping-list">
        <h1>Shopping List for {this.props.name}</h1>
        <ul>
          <li>Instagram</li>
          <li>WhatsApp</li>
          <li>Oculus</li>
        </ul>
      </div>
    );
  }
}
 
// Example usage: <ShoppingList name="Mark" />
cs

 

잠시 후에 XML 유사한 태그를 접하게 것입니다.  당신의 Component를 사용하여 React 통해 렌더링을  것 입니다. - React는 데이터가 변경될 때마다 해당 Component 효율적으로 데이터를 업데이트하고 렌더링 것입니다.


위 예제에서 ShoppingList React component class 또는 React component type 입니다. Component props라는 매개 변수를 사용하고 render 메서드를 통해 표시 계층 구조를 반환해 줍니다. 


render 메서드는 렌더링 정보를 반환하고, React 해당 정보를 가져 와서 화면에 렌더링합니다. 특히, render React Element 반환하는데, 이것은 렌더링 내용에 대한 간단한 정보을 담고 있습니다.  대부분의 React 개발자는 JSX라는 특수 구문을 사용하여 이러한 구조를 쉽게 작성할 있습니다.  

예를 들면, <div /> 구문은 빌드 React.createElement ( 'div') 변환됩니다. 아래 예와 같습니다.


1
2
3
4
return React.createElement('div', {className: 'shopping-list'},
  React.createElement('h1', ...),
  React.createElement('ul', ...)
);
cs


JSX 내부의 중괄호 안에 JavaScript 를 포함 할 수 있습니다. React Element는 변수에 저장되거나, 여러분의 프로그램 에서 전달 될 수 있는 JavaScript 객체입니다


ShoppingList component는 기본으로 제공되는 DOM component로 렌더링하지만, <ShoppingList />와 같이 사용하여 사용자 지정 React component들을 쉽게 구성 할 수 있습니다. 각 component들은 캡슐화되어 독립적으로 작동 할 수 있으므로 간단한 component들로 복잡한 UI를 구성할 수 있습니다.


 

시작하기


다음 예제로 시작하십시오 : Starter Code.

위 소스는 우리가 지금 만들려고 하는 게임의 큰 틀만 있습니다. Style(CSS)을 포함하고 있으니, JavaScript 만 신경 쓰면 됩니다

여기서 중요한 세 가지 Component 가 있습니다.

    • Square

    • Board

    • Game


Square component는 하나의 <div>를 렌더링하고, Board 9 개의 Square들을 렌더링하며, Game component는 나중에 자리를 표시할 보드를 렌더링합니다. 현 시점시점에서는 Component간에 상호작용하지 않습니다.

(JS 파일의 끝 부분에는 나중에 사용하게 될 도우미 함수 calculateWinner가 정의되어 있습니다.)


 

Props를 통한 데이터 전달


일단, React 접해 보기 위해서, Board component에서 Square component 데이터를 전달해 보도록 하겠습니다. Board component renderSquare 메소드 에서 <Square value = {i} /> 반환하도록 코드를 변경 다음 Square render 메소드의 {/ * TODO * /} 부분을 {this.props.value} 바꾸면 값이 표시됩니다.


:




변경 후: Square에 숫자가 표시되는 걸 확인할 수 있습니다.




상호작용하는 컴포넌트

 

그럼 Square component 클릭하면 "X" 채워지도록 만들어 봅시다. Square 클래스의 render () 함수에서  opening 태그 부분을 다음과 같이 변경하시기 바랍니다.


1
<button className="square" onClick={() => alert('click')}>
cs

여기서 새로운 JavaScript문법인(ES6에서 도입) Arrow function 문법을 사용했습니다. 이제 Square을 클릭하면 브라우저에서 경고가(alert) 표시될 것입니다.


React Component들은 생성자에서 this.state를 설정하여 state 정보를 가질 수 있습니다. 이 정보는 Component를 위한 Private 정보로만 사용되어야 합니다

이제 Square의 현재 값을 state에 저장하고, Square을 클릭하면 변경되도록 하겠습니다. 그럼 먼저 클래스에 생성자를 추가하여 state를 초기화합니다.


1
2
3
4
5
6
7
8
9
class Square extends React.Component {
  constructor() {
    super();
    this.state = {
      value: null,
    };
  }
  ...
}
cs



JavaScript 클래스에서는 서브 클래스의 생성자를 정의할 때, 명시적으로 super();을 호출 해야합니다.


이제 this.props.value 대신 this.state.value를 표시하도록 render 메서드를 변경하고, alert() 대신 () => this.setState ({value : 'X'})로 이벤트 처리를 변경합니다.


1
2
3
<button className="square" onClick={() => this.setState({value: 'X'})}>
    {this.state.value}
</button>
cs

 

this.setState가 호출 될 때마다 component에 대한 업데이트가 예정되어 있으므로 React는 전달받은 state를 업데이트하고 하위 component들과 함께 다시 렌더링됩니다. 

component가 렌더링될 때 this.state.value 'X'가 되어 그리드에 X가 표시됩니다.


Square을 클릭하면, Square에 'X'가 나타납니다


 

개발자 툴들


Chrome Firefox React Devtools 확장 프로그램을 사용하면 브라우저 devtools에서 React 구성 요소 트리를 검사 할 수 있습니다




도구를 사용하면 트리의 모든 Component props state 검사 있습니다


CodePen에서는 여러 프레임을 사용해서  해당 툴이 작동하지 않지만, CodePen 로그인하고 스팸 방지를 위해 전자 메일을 확인할 경우에는 Change View > Debug 이동하여 탭에서 코드를 다음 devtools 작동하면 됩니다.  지금 바로 사용할 필요는 없지만 이렇게 할 수 있다는 것만 알아도 좋습니다.



Lifting State Up


우리는 이제 tic-tac-toe 게임을 위한 기본적인 빌딩 블록을 가지게 되었습니다. 그러나 아직까지는  Square component state가 캡슐화되어 있습니다. 제대로 작동하는 게임을 되기 위해서는  플레이어가 게임에서 승리했는지 확인할 수 있고, X O 네모 칸에 표시 될 수 있어야 합니다. 누군가가 승리했는지 확인하기 위해 Square component들 모두 확인하는 것보다는 곳에서 9 개의 모든 Square 값을 가져야 할 것입니다.  


아마도 여러분은 지금 Board에서  Square 현재 state 어떤지 조사해야 한다고 생각할 수도 있습니다.  React에서 기술적으로 가능하지만, 이런 패턴은 코드를 이해하기 어렵게 만들고, 깨지기 쉬우며, 리팩토링하기가 어려워지기 때문에 추천하지 않습니다


대신에 , 여기서는 가장 좋은 해결책으로 state Square 아닌 Board component에서  저장하는 것입니다. - 그래서 Board component에서  Square 어떻게 표시해야하는지 알려줄 있게 됩니다.  


여러 하위 component들에서 데이터를 집계하거나 하위 두 component들 간에 서로 통신하도록 하기 위해서는, 상위 Component에서 state 가지게 있도록 해야합니다.  그렇게 되면 Parent props 통해 Child에게 상태를 다시 전달할 있으므로 Child Component 간에 그리고 Parent 항상 서로 동기화될 수 있습니다


이와 같이 state 위쪽으로 올리는 것은 React component 리팩토링 사용하는 일반적인 방법입니다.  이번에 활용  보도록 하겠습니다.  9 개의 Square 해당하는 9 개의 (null) 있는 배열을 포함하는 Board 초기  state 추가하십시오.


1
2
3
4
5
6
7
8
class Board extends React.Component {
  constructor() {
    super();
    this.state = {
      squares: Array(9).fill(null),
    };
  }
}
cs


나중에 배열을 채우게 되면 Board 아래와 같이 됩니다.


1
2
3
4
5
[
  'O'null'X',
  'X''X''O',
  'O'nullnull,
]
cs


Square 값은 아래와 같이 전달합니다.


1
2
3
renderSquare(i) {
  return <Square value={this.state.squares[i]} />;
}
cs



그리고 다시 Square에서 this.props.value를 다시 사용하도록 변경하십시오. 이제 Square을 클릭했을 때 발생하는 부분이 바뀌어야 합니다.  Board component는 squares 배열을 가지고 있습니다. 이 뜻은 SquareBoardstate 를 업데이트 할 수 있는 방법이 필요로 하다는 뜻입니다. ComponentstatePrivate으로 관리 되므로 Boardstate 을 직접 업데이트 할 수 없습니다. 그래서 일반적인 패턴은 Square을 클릭 할 때, Board에서 Square로 함수를 전달하는 것입니다. renderSquare를 다시 다음과 같이 변경합니다.


1
return <Square value={this.state.squares[i]} onClick={() => this.handleClick(i)} />;
cs



이제 Board에서 Square로 두 개의 props를 전달합니다. : value onClick. 

후자는 Square가 호출 할 수 있는 함수입니다. Square에 있는 render 부분을 다음과 같이 변경합니다. 


1
<button className="square" onClick={() => this.props.onClick()}>
cs


위 코드의 의미는, Square을 클릭하면 Parent가 전달한 onClick 함수가 호출된다는 것입니다.  여기서는 onClick이 특별한 의미가 없지만, on으로 시작하고 handle을 사용하여 구현한 것들은 handler props 입니다. Square을 클릭 해보십시오. - 아직 handleClick을 정의하지 않았으므로 오류가 발생합니다. Board 클래스에 handleClick()을 구현해봅시다.:


1
2
3
4
5
handleClick(i) {
  const squares = this.state.squares.slice();
  squares[i] = 'X';
  this.setState({squares: squares});
}
cs


여기서, 우리는 .slice () 호출하여 기존 배열을 변경하는 대신 squares 배열을 복사했습니다.  불변성의 중요성의 이유를 배우기를 원하면, 다음 섹션을 넘어 가십시오


이제 square들을 클릭하여, squares 배열을 다시 채울  있기 때문에,  Square 아닌 Board Component state를 저장,  게임을 계속 만들 있습니다. Board state 변경 때마다 Square component가 자동으로 다시 렌더링됩니다


Square 이상 자체 state 유지하지 않습니다. Square 클릭했을 Parent인 Board 로부터 state 값을 받고, Parent에게 알립니다. 우리는 이런 Component들 controlled components”라 부릅니다.



왜 불변성이 중요한가.

 

이전 코드 예제에서 .slice () 연산자를 사용하여 squares 배열을 변경하기 전에 복사하고 기존 배열의 변형을 방지하는 것이 좋다고 했습니다. 이것이 의미하는 것이 무엇이고, 왜 그것이 중요한지에 대해 배워보도록 하겠습니다.


일반적으로 데이터를 변경하는 방법은 두 가지가 있습니다. 첫 번째 방법은 변수의 값을 직접 변경하여 데이터를 변경하는 것입니다. 두 번째 방법은 변경 내용이 포함 된 개체의 복사본을 만들어 데이터를 바꾸는 것입니다.


원본의 변경이 있는 데이터 변경


1
2
3
var player = {score: 1name'Jeff'};
player.score = 2;
// Now player is {score: 2, name: 'Jeff'}
cs



원본의 변경이 없는 데이터 변경


1
2
3
4
5
6
7
var player = {score: 1name'Jeff'};
 
var newPlayer = Object.assign({}, player, {score: 2});
// Now player is unchanged, but newPlayer is {score: 2, name: 'Jeff'}
 
// Or if you are using object spread, you can write:
// var newPlayer = {...player, score: 2};
cs



최종 결과는 동일하지만 원본의 변경이 없는 경우에, Component 전반적인 응용 프로그램의 성능을 향상시키는 도움이 되는 추가 이점이 있습니다.


변경 추적 


불변성이 아닌 객체가 변경되었는지 여부를 확인하는 것이 복잡한 이유는 해당 객체에서 직접 변경이 이루어지기 때문입니다. 그래서 현재 객체를 이전 복사본과 비교하여 전체 객체 트리를 비교하며,  변수의 값을 비교해야 해야 하기 때문입니다.  과정은 점점 복잡해질 있습니다


하지만 불변 객체는 변경 여부를 확인하는 방법이 매우 쉽습니다. 객체가 이전에 참조한 객체와 다르면 객체가 변경된 것입니다. 그게 전부입니다



React에서 언제 다시 렌더링할지 결정


React에서 불변성 가장 이점은 단순하고 순수한 Component 빌드 때입니다. 불변 데이터는 변경 여부를 쉽게 ​​판별 있기 때문에 Component 언제 다시 렌더링되어야 하는지를 결정하는 도움이 됩니다.


순수 컴포넌트를 빌드하는 방법을 배우려면 shouldComponentUpdate () 살펴보십시오. 또한 불변의 데이터를 엄격하게 적용하고 싶으면, Immutable.js 라이브러리를 살펴보십시오.



함수형 컴포넌트


다시 프로젝트로 돌아와, 이제 Square에서 생성자를 삭제할 있습니다. 이상 필요하지 않습니다. 실제로 React에서는 render 메서드로만 구성되는 Square 같은 component 유형들에 대해 stateless functional components라는 간단한 문법을 지원합니다. React.Component 확장하는 클래스를 정의하는 대신, 간단하게 props 사용하고 렌더링 되어야하는 것을 반환하는 함수를 작성하면 됩니다.


1
2
3
4
5
6
7
function Square(props) {
  return (
    <button className="square" onClick={() => props.onClick()}>
      {props.value}
    </button>
  );
}
cs



이제, this.props를  props 변경해야 합니다.  

여러분의 어플리케이션에서 많은 Component들을 functional component 만들 있을 것이고, React는 향후에는 이 함수형 컴포넌트들을  최적화 시킬 것입니다.



순서 가져오기


현재 우리 게임은 'X' 만 플레이 할 수 있는 결함을 가지고 있습니다.  수정해 보도록 합시다


첫 번째 이동은 'X'로 기본 설정합니다. Board 생성자에서 시작 state를 수정합니다.


1
2
3
4
5
6
7
8
class Board extends React.Component {
  constructor() {
    super();
    this.state = {
      ...
      xIsNext: true,
    };
  }
cs



이동할 때마다 xIsNext 부울 값을  토글하여 state에 저장합니다.  이제 xIsNext의 값을 토글할 수 있도록 handleClick 함수를  수정합니다. 


1
2
3
4
5
6
7
8
handleClick(i) {
  const squares = this.state.squares.slice();
  squares[i] = this.state.xIsNext ? 'X' : 'O';
  this.setState({
    squares: squares,
    xIsNext: !this.state.xIsNext,
  });
}
cs



이제야 'X' 'O'가 순서대로 사용됩니다. 다음은, 누가 다음인 출력하기 위해 Boardrender 함수에 있는  "status" 텍스트를 변경하겠습니다. 


 

승리자 선언

 

지금부터 게임에서 언제 승리하는지 보여줍시다. 9 개의 값 목록을 전달해 주는 calculateWinner (squares) 도우미 함수가 맨 아래에 제공됩니다. Boardrender function 에서 이 기능을 호출하여 게임에서 이긴 사람이 있는지 확인하고, 누군가가 이기면 상태 텍스트에 "Winner : [X / O]"가 표시되게 할 수 있습니다.:


1
2
3
4
5
6
7
8
9
10
render() {
  const winner = calculateWinner(this.state.squares);
  let status;
  if (winner) {
    status = 'Winner: ' + winner;
  } else {
    status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
  }
  ...
}
cs

 

누군가가 이미 게임에 이겼거나, Square가 모두 채워져 있으면 끝내거나 무시하록 handleClick을 변경하겠습니다.


1
2
3
4
5
6
7
handleClick(i) {
  const squares = this.state.squares.slice();
  if (calculateWinner(squares) || squares[i]) {
    return;
  }
  ...
}
cs



축하합니다

이제 동작하는 tic-tac-toe 게임이 완성되었습니다

이를 통해 React의 기본을 알게 되었습니다. 아마 당신은 여기에서 진정한 승자 일 겁니다.



Storing a History


그럼 이제, Board에 예전 state 다시 방문하여, 이전 움직임 이후에 어떤 모습인지 확인할 있게 해보도록 하겠습니다. 이동 할 때마다  squares 배열을 만들고 있으므로 이전 보드 상태를 쉽게 저장할 있습니다. 


state에서 다음과 같이 state에 객체를 저장하려고 합니다.


1
2
3
4
5
6
7
8
9
history = [
  {
    squares: [null x 9]
  },
  {
    squares: [... x 9]
  },
  ...
]
cs


우리는 최상위에 있는 Game Component에  이동 목록을 표시하기를 원합니다. 그래서 Square에서 Board state를 올렸던 것처럼, Board에서 Game으로 다시 끌어 올려 봅시다 - 그래서 우리는 필요로 하는 모든 정보를 최상위 레벨에서 갖습니다


먼저 게임의 초기  state 설정합니다.


1
2
3
4
5
6
7
8
9
10
11
12
class Game extends React.Component {
  constructor() {
    super();
    this.state = {
      history: [{
        squares: Array(9).fill(null)
      }],
      xIsNext: true
    };
  }
  ...
}
cs



그런 다음 Board를 변경하여 생성자를 제거하고, props을 통해 squares 배열을 가져오고, 이전 Square 변경과 같이 Game 위한 특별한 onClick props을 갖도록 합니다. Square의 위치를 ​​클릭 핸들러를 통해 전달하여 클릭 한 Square을 알 수 있습니다.


1
return <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />;
cs

 

Gamerender 는 가장 최근의 기록 항목을 볼수 있고, game status을 계산할 수 있습니다.


 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const history = this.state.history;
const current = history[history.length - 1];
const winner = calculateWinner(current.squares);
 
let status;
if (winner) {
  status = 'Winner: ' + winner;
else {
  status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
...
<div className="game-board">
  <Board
    squares={current.squares}
    onClick={(i) => this.handleClick(i)}
  />
</div>
<div className="game-info">
  <div>{status}</div>
  <ol>{/* TODO */}</ol>
</div>
cs



handleClick은 새 히스토리 항목을 연결하여 새로운 히스토리 배열을 작성하여 스택에 새 항목을 푸시 할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
handleClick(i) {
  const history = this.state.history;
  const current = history[history.length - 1];
  const squares = current.squares.slice();
  if (calculateWinner(squares) || squares[i]) {
    return;
  }
  squares[i] = this.state.xIsNext ? 'X' : 'O';
  this.setState({
    historyhistory.concat([{
      squares: squares
    }]),
    xIsNext: !this.state.xIsNext,
  });
}
cs



이제 Board renderSquare render만 필요 합니다. 상태 초기화 및 클릭 핸들러는 모두 Game에 있기 때문입니다.


 

이동 표시


지금까지 Game에서 만들어진 이전 이동 보여 드리겠습니다. React 요소는 first-class  JS 객체이므로 저장하거나 전달할 있습니다. React에서 여러 항목을 렌더링하기 위해 React Element들 배열을 전달합니다. 배열을 빌드하는 가장 일반적인 방법은 데이터 배열을 매핑하는 것입니다. Game render 메서드에서 그렇게 해보도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
const moves = history.map((step, move) => {
  const desc = move ?
    'Move #' + move :
    'Game start';
  return (
    <li>
      <a href="#" onClick={() => this.jumpTo(move)}>{desc}</a>
    </li>
  );
});
...
<ol>{moves}</ol>
cs



히스토리의 각 단계마다 목록 항목 <li>을 만들고 그 안에 링크가 없는 <a> (href = "#") 곧 구현할 클릭 핸들러가 있습니다. 이 코드를 사용하면 게임에서 만들어진 동작 목록과 함께 다음과 같은 경고 메시지가 표시됩니다.

 

경고 : 배열 또는 반복기의 각 Child에는 고유 한 "key" props이 있어야합니다. "Game"의 렌더링 메소드를 확인하십시오.


그럼 이 경고의 의미에 대해 이야기 봅시다.

 

Keys


아이템 목록을 렌더링하면, React 항상  아이템 대한 정보를 목록에 저장합니다. state가 있는 Component 렌더링하는 경우에는 해당 state 저장해야 하며 Component 구현하는 방법에 관계없이 React 참조를 기본 네이티브 뷰에 저장합니다


목록을 업데이트하면 React 변경된 사항을 확인해야 합니다. 목록의 항목을 추가, 제거, 재배치 또는 업데이트 있습니다.


이제 변환되는 것을 상상해보십시오.


변환


1
2
<li>Alexa: tasks left</li>
<li>Ben: tasks left</li>
cs


변환


1
2
3
<li>Ben: tasks left</li>
<li>Claudia: tasks left</li>
<li>Alexa: tasks left</li>
cs


사람의 눈에는 위 변화는 AlexaBen의 위치를 바꿔주고, Claudia가 추가된 것처럼 보일 것이다. 그러나 React는 컴퓨터 프로그램 일 뿐이고 의도 한 바를 모릅니다. 결과적으로 React는 목록의 각 요소에 대해 key을 지정하도록 요구합니다.이 특성은 ComponentSibling과 구분하기 위해서 입니다. 이 경우, Alexa, Ben, Claudia는 합리적인 키가 될 수 있습니다. 항목이 데이터베이스의 개체에 해당하는 경우 데이터베이스 ID는 일반적으로 좋은 선택입니다.


1
<li key={user.id}>{user.name}: {user.taskCount} tasks left</li>
cs


key React 의해 예약 특별한 속성입니다 (ref 함께, 고급 기능). 요소가 만들어지면 React 속성을 가져와 키를 반환 요소에 직접 저장합니다. 그것이 props 일부인 것처럼 보일지라도 this.props.key 참조 수는 없습니다. React key 자동으로 사용하여 업데이트 Child 결정합니다. Component 자체 key 대해 질의 있는 방법은 없습니다


목록이 다시 표시되면, React 버전의 요소를 가져 와서 이전 목록에서 일치하는 key 있는지 요소를 찾습니다. 세트에 key 추가되면 Component 작성됩니다. key 제거되면 구성 요소가 파괴됩니다. Keys React에게 컴포넌트의 신원을 알려서 rerenders 전체에서 상태를 유지할 있도록 합니다. Component key 변경하면 완전히 파손되어 새로운 상태로 다시 작성됩니다


동적 목록을 작성할 때마다 적절한 키를 할당하는 것이 강력하게 추천합니다. 적절한 키가 없으면 데이터 재구성을 고려해야 수도 있습니다


어떤 key 지정하지 않으면 React 경고를 표시하고 배열 인덱스를 key 사용합니다. 목록에서 요소의 순서를 바꾸거나 항목의 아래에 있는 항목을 추가 / 제거하는 경우 올바른 선택이 아닙니다. 명확하게 key = {i} 전달하면 경고가 사라지지만 동일한 문제가 발생하므로 권장하지 않습니다


Component key들은 전역적으로 고유 필요는 없으며, 직접적인 sibling과의 관계에서는 고유 해야합니다.

 

시간 여행 구현 


이동 목록의 경우 단계마다 고유 ID 이미 있습니다. 이동이 발생한 시기의 번호입니다. 키를 <li key = {move}> 추가하면 key 경고가 사라집니다.


jumpTo 정의되지 않았기 때문에 이동 링크 하나를 클릭하면 오류가 발생합니다. 게임의 상태에 새로운 키를 추가하여 현재 보고있는 단계를 알려줍니다. 먼저 stepNumber : 0 초기 state 추가 다음 jumpTo 사용하여 해당 상태를 업데이트하도록 합시다.


우리는 또한 xIsNext 업데이트하려고 합니다. 이동 번호의 인덱스가 짝수이면 xIsNext true 설정합니다.


1
2
3
4
5
6
jumpTo(step) {
  this.setState({
    stepNumber: step,
    xIsNext: (step % 2) ? false : true,
  });
}
cs

그런 다음 stepNumber : history.length handleClick의 상태 업데이트에 추가하여 새 이동이 수행되면 stepNumber를 업데이트 하겠습니다. 이제 render를 수정하여 히스토리에서 해당 단계를 읽을 수 있게 하겠습니다.


1
const current = history[this.state.stepNumber];
cs


이제 이동 링크를 클릭하면 Board가 즉시 업데이트 되어 그 시간에 게임이 어떻게 보였는지 보여줍니다. 현재의 board state을 읽을 때, stepNumber를 인식하도록 handleClick을 업데이트하여 보드에 시간을 두고 다시 돌아와 새로운 항목을 만들 수 있습니다. (힌트 : handleClick의 맨 위에서 역사의 추가 요소를 .slice ()하는 것이 가장 쉽습니다.)

 


마무리


이제 tic-tac-toc 게임을 만들었습니다.

    • tic-tac-toe 게임을 해보세요.

    • 한 플레이어가 게임에서 이기면 화면에 표시됩니다.

    • 게임 중 동작의 이력을 저장하고,

    • 플레이어는 이전 버전의 게임 보드를 보기 위해 시간을 거슬러 올라갈 수 있습니다.


잘 했어! 우리는 당신이 지금 React가 어떻게 작동하는지에 관해 알맞은 생각을 가지고 있다고 느끼기를 바랍니다.

추가 시간이 있거나 새로운 기술을 연습하고 싶다면 다음과 같이 개선 할 수 있는 아이디어가 있습니다. 어려움이 갈수록 커집니다.


1.         "6"대신 "(1, 3)"형식으로 이동 위치를 표시하십시오.

2.        이동 목록에서 현재 선택된 항목을 굵게 표시하십시오.

3.        보드를 다시 작성하여 두 개의 루프를 사용하여 Square을 하드 코딩하는 대신 사용하십시오.

4.        오름차순 또는 내림차순으로 동작을 정렬 할 수 있는 전환 버튼을 추가하십시오.

5.        누군가가 이기면 승리를 가져온 세 개의 Square을 강조 표시합니다.

 

+ Recent posts