react 1

https://reactjs.org/tutorial/tutorial.html

我的体会,这篇入门React真复杂,里面的原理也说得云里雾里,不怎么适合初学者入门

Before We Start

What We’re Building

Today, we’re going to build an interactive tic-tac-toe game.
今天我们做一个交互的 tic-tac-toe的游戏

If you like, you can check out the final result here: Final Result. Don’t worry if the code doesn’t make sense to you yet, or if it uses an unfamiliar syntax. We will be learning how to build this game step by step throughout this tutorial.
Try playing the game. You can also click on a button in the move list to go “back in time” and see what the board looked like just after that move was made.
Once you get a little familiar with the game, feel free to close that tab, as we’ll start from a simpler template in the next sections.
如果你喜欢,你能检查最终的结果:[结果]。(https://codepen.io/gaearon/pen/gWWZgR?editors=0010),不要担心你不用现在来写这个代码。我们将要学习如何来写这个代码通过这个指南。你能交互方式来玩这个而游戏。

Prerequisites

We’ll assume some familiarity with HTML and JavaScript, but you should be able to follow along even if you haven’t used them before.
我们假设你熟悉html和javscript,但你应该能够跟着下面做

If you need a refresher on JavaScript, we recommend reading this guide. Note that we’re also using some features from ES6, a recent version of JavaScript. In this tutorial, we’re using arrow functions, classes, let, and const statements. You can use the Babel REPL to check what ES6 code compiles to.
如果你需要再看一下JavaScript ,我们建议你在读一下这个指南,注意我们试用ES6的特型,是当前的JavaScript版本。在这个向导中,我们使用额箭头函数(=>),类 class,let 关键字,const关键字。你使用Babel REPL检查什么ES6的代码能被编译。
(哇哈哈,看到这个工具链了么?复杂么?)

How to Follow Along

There are two ways to complete this tutorial: you could either write the code right in the browser, or you could set up a local development environment on your machine. You can choose either option depending on what you feel comfortable with.
这里有2条路来完成这个指南:你写代码在浏览器中,或者你搭建好本地挨罚环境。你可以选一个让你觉得爽的。

If You Prefer to Write Code in the Browser
如果你想在浏览器中写代码

This is the quickest way to get started!
这个是最快上路的办法

First, open this starter code in a new tab. It should display an empty tic-tac-toe field. We will be editing that code during this tutorial.
第一,打开这个开始代码在新的页面内,这个能显示一个空的tic-tac-toe区域,我们开始编辑代码。
You can now skip the next section about setting up a local development environment and head straight to the overview.
你开始跳过设置本地开发环境,然后开始咯~

If You Prefer to Write Code in Your Editor
如果你打算用你的编辑器来写代码

Alternatively, you can set up a project on your computer.
可选的,你开始一个工程在你的计算机上。
Note: this is completely optional and not required for this tutorial!
注意:这个可选
This is more work, but lets you work from the comfort of your editor.

If you want to do it, here are the steps to follow:

  1. Make sure you have a recent version of Node.js installed.
  2. Follow the installation instructions to create a new project.
    你安装好nodejs了么?然后开始
npm install -g create-react-app
create-react-app my-app
  1. Delete all files in the src/ folder of the new project (don’t delete the folder, just its contents).
    删除所有文件,不要删除文件夹呀,只是把内容删除掉哟
cd my-app
rm -f src/*
  1. Add a file named index.css in the src/ folder with this CSS code.
    添加index.css 在src中
  2. Add a file named index.js in the src/ folder with this JS code.
    添加一个index.js在scr中
  3. Add these three lines to the top of index.js in the src/ folder:
    编辑index.js 文件包含如下内容
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

Now if you run npm start in the project folder and open http://localhost:3000 in the browser, you should see an empty tic-tac-toe field.
现在你运行 npm start 可以看到东东了
(我运行了一下,是看到了,good)

Overview

What is React?

什么是React
React is a declarative, efficient, and flexible JavaScript library for building user interfaces.
React 是一个陈述式,高效的,可扩展的JavaScript库。来构建用户界面

React has a few different kinds of components, but we’ll start with React.Component subclasses:
React有一些不同的组建,我们开始看一下React.Component

class ShoppingList extends React.Component {
// 扩展React.Component 叫做 ShoppingList
// 注意变量的命名规则
  render() {
  // render 渲染,很神奇把,php的YII框架也是这个名字
    return (
    //返回一个列表,classname 叫做 shopping-list的东东
      <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" />

We’ll get to the funny XML-like tags in a second. Your components tell React what you want to render – then React will efficiently update and render just the right components when your data changes.
我们得到一个有趣的XML类似的标记。你的组建告诉React你打算什么来做展示(渲染 render)。然后React将高效的更新和渲染这个正确的组件,当你的数据改变的时候。(这里注意React高效的原因是,他负责了数据双向绑定的时候,当数据绑之后,他去刷界面内容)
Here, ShoppingList is a React component class, or React component type. A component takes in parameters, called props, and returns a hierarchy of views to display via the render method.
这里,ShoppingList 是一个React组件类。或者 React组件类型(这里我觉得的写React component 比较好)。一个组件可以有参数,之叫做属性。返回一个view的层次,来显示内容。

The render method returns a description of what you want to render, and then React takes that description and renders it to the screen. In particular, render returns a React element, which is a lightweight description of what to render. Most React developers use a special syntax called JSX which makes it easier to write these structures. The

syntax is transformed at build time to React.createElement(‘div’). The example above is equivalent to:
render方法返回一个描述,你什么打算显示。然后React按照这个描述来在显示器上显示。这个特别的,render返回一个 React元素。在这里是一个轻量级的描述对于render。 很多 React开发扎使用一个特别的语法叫做JSX,这个更加容易来写这个结构,
语法表示建造时间到React.createElement(‘div’)。这个例子和下面类似

return React.createElement('div', {className: 'shopping-list'},
  React.createElement('h1', /* ... h1 children ... */),
  React.createElement('ul', /* ... ul children ... */)
);

下面两者等价(用babel转换)

React.createElement(
  "div",
  { className: "shopping-list" },
  React.createElement(
    "h1",
    null,
    "Shopping List for ",
    props.name
  ),
  React.createElement(
    "ul",
    null,
    React.createElement(
      "li",
      null,
      "Instagram"
    ),
    React.createElement(
      "li",
      null,
      "WhatsApp"
    ),
    React.createElement(
      "li",
      null,
      "Oculus"
    )
  )
);
<div className="shopping-list">
  <h1>Shopping List for {props.name}</h1>
  <ul>
    <li>Instagram</li>
    <li>WhatsApp</li>
    <li>Oculus</li>
  </ul>
</div>

If you’re curious, createElement() is described in more detail in the API reference, but we won’t be using it directly in this tutorial. Instead, we will keep using JSX.
如果你好奇,createElement()更加详细的信息请参考API,但是我们在这个向导中不会直接使用,我们会使用JSX.

You can put any JavaScript expression within braces inside JSX. Each React element is a real JavaScript object that you can store in a variable or pass around your program.
你能试用任何JS的表达式在JSX中。每个React元素都是一个JS对象,你能保存这个变量在你的程序中。

The ShoppingList component only renders built-in DOM components, but you can compose custom React components just as easily, by writing . Each component is encapsulated so it can operate independently, which allows you to build complex UIs out of simple components.
Shopping 组件只能渲染内置的DOM组件,但你可以很容易的自己创建React组件。写 每个组件被封装,可以被独立操作。这个允许你创建复杂的UI用简单的组件。

Getting Started

来吧
Start with this example: Starter Code.
我们看这个例子
It contains the shell of what we’re building today. We’ve provided the styles so you only need to worry about the JavaScript.
这个包含我们今天要编写的东西,我们提供了这个风格,你不要担心JS

In particular, we have three components:
- Square (方块)
- Board(棋盘)
- Game(游戏)

The Square component renders a single , the Board renders 9 squares, and the Game component renders a board with some placeholders that we’ll fill in later. None of the components are interactive at this point.
这个棋盘组件是展示位单一的 ,这个棋盘有9个方块。这个Game组件演示一个棋盘和一些位置,我们能够填满这个。没有组件能被交互。

Passing Data Through Props

通过属性来传递数据
Just to get our feet wet, let’s try passing some data from the Board component to the Square component.
春江水暖鸭先知(把我们的脚弄湿),然我们来传递一些数据从Board到Square

In Board’s renderSquare method, change the code to pass a value prop to the Square:
在Board的rederSqure方法,改变代码把一个数据传给Square

class Board extends React.Component {
  renderSquare(i) {
    return <Square value={i} />;
  }
  //总是返回了,但是也不知道<Squre value={i}> 什么意思

Then change Square’s render method to show that value by replacing {/* TODO */} with {this.props.value}:
这个改变了Squre的render方法显示value的值

class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {this.props.value}
        //this.props的值
      </button>
    );
  }
}

然后你就可以看到数据了
之前是
这里写图片描述
现在是
这里写图片描述
我测试成功了

An Interactive Component

一个交互性的组件
Let’s make the Square component fill in an “X” when you click it. Try changing the button tag returned in the render() function of the Square like this:
我们希望Square 组件填充X,当你点击整个儿,这个改变了button的tag,返回render函数,类似于下面

class Square extends React.Component {
  render() {
    return (
      <button className="square" onClick={() => alert('click')}>
      //点击了之后,跳出一个对话框,你点击了
        {this.props.value}
      </button>
    );
  }
}

If you click on a square now, you should get an alert in your browser.
如果你点击了squre,那么你可以得到一个alert
This uses the new JavaScript arrow function syntax. Note that we’re passing a function as the onClick prop. Doing onClick={alert(‘click’)} would alert immediately instead of when the button is clicked.
这个使用了js的箭头函数表达式。注意我们传递了一个函数给onClick属性。在onClick={alert(‘click’)}没有alert立刻,除非这个button被点击了。

React components can have state by setting this.state in the constructor, which should be considered private to the component. Let’s store the current value of the square in state, and change it when the square is clicked.

React 组件有一个state属性,来设置this.state在构造函数中,这个需要考虑是私有的。保存当前的squre的状态,改变当squre被点击的时候。

First, add a constructor to the class to initialize the state:
首先,我们添加一个构造函数到class中

class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null,
    };
    //初始化,这个value是null,为什么是null,不是0?
  }

  render() {
    return (
      <button className="square" onClick={() => alert('click')}>
        {this.props.value}
      </button>
    );
   //返回这个value
  }
}

In JavaScript classes, you need to explicitly call super(); when defining the constructor of a subclass.
在JavaScript的类中,你需要使用super(),在子类中定义一个构造体

Now change the Square render method to display the value from the current state, and to toggle it on click:

  • Replace this.props.value with this.state.value inside the

  • tag. Replace the () => alert() event handler with () =>
    this.setState({value: ‘X’}). Now the tag looks like this:
    修改代码如下所示

class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null,
    };
  }

  render() {
    return (
      <button className="square" onClick={() => this.setState({value: 'X'})}>
        {this.state.value}
      </button>
    );
  }
}

Whenever this.setState is called, an update to the component is scheduled, causing React to merge in the passed state update and rerender the component along with its descendants. When the component rerenders, this.state.value will be ‘X’ so you’ll see an X in the grid.
If you click on any square, an X should show up in it.
无论调用 this.setState,组件会被更新。原因是React整合这个state的跟新,reduce会这个组件。当组件被再次render的时候,这个this.statue值会变成X,你能够在网格内看到X

Developer Tools

开发工具
The React Devtools extension for Chrome and Firefox lets you inspect a React component tree in your browser devtools.
React Devtools 对于Chrome的扩展,你能检查React的组件树

这里写图片描述

It lets you inspect the props and state of any of the components in your tree.
After installing it, you can right-click any element on the page, click “Inspect” to open the developer tools, and the React tab will appear as the last tab to the right.
这个你能查看组件的状态
在安装好之后,你点击页面元素,年级inspect在打开的开发工具,这个React tab 会被现实正常。

However, note there are a few extra steps to get it working with CodePen:
注意,这个理由一些扩展的步骤让你可以比较好的使用CodePen

  1. Log in or register and confirm your email (required to prevent spam).
    Click the “Fork” button.
  2. Click “Change View” and then choose “Debug mode”.
  3. In the new tab that opens, the devtools should now have a React tab.

    登录注册,然后点Fork按钮
    点改变Change view,选择debug mode
    在新的tab中,你可以看到开发工具有了React tab

    Lifting State Up

We now have the basic building blocks for a tic-tac-toe game. But right now, the state is encapsulated in each Square component. To make a fully-working game, we now need to check if one player has won the game, and alternate placing X and O in the squares. To check if someone has won, we’ll need to have the value of all 9 squares in one place, rather than split up across the Square components.
你有了基本的建立block的技能,但这个状态被封装了对于每个Square组件。为了达到最终的状态,我们需要检查,玩家是否赢了这个预习,然后用X和O在方框内显示。我们需要所有的9个方框内。

You might think that Board should just inquire what the current state of each Square is. Although it is technically possible to do this in React, it is discouraged because it tends to make code difficult to understand, more brittle, and harder to refactor.
你也许开始想了棋盘应该是被检查状态的,当前状态,这个是一个技术的可能在React中,这个不被鼓励的,因为这个让代码难以理解。难以被重构

Instead, the best solution here is to store this state in the Board component instead of in each Square – and the Board component can tell each Square what to display, like how we made each square display its index earlier.

替代的,这个最好的方法是保存这个状态在Board组件替代每个Square组件。Board组件告诉每个Square应该显示什么。

When you want to aggregate data from multiple children or to have two child components communicate with each other, move the state upwards so that it lives in the parent component. The parent can then pass the state back down to the children via props, so that the child components are always in sync with each other and with the parent.
当你集合数据从讴歌孩子有2个孩子组件通讯每个人,移动状态到这个活动的父组件下。这个父能把状态传递给孩子通过props,所以孩子组件能总是被同步和父组件。

Pulling state upwards like this is common when refactoring React components, so let’s take this opportunity to try it out. Add a constructor to the Board and set its initial state to contain an array with 9 nulls, corresponding to the 9 squares:

我们开始改代码了,重构React组件。添加构造函数Board,设置这个初始化状态包含一个9null的数组,然后给9个方框。

v16.1.1GitHub
Tutorial: Intro To React
Before We Start
What We’re Building
Today, we’re going to build an interactive tic-tac-toe game.
If you like, you can check out the final result here: Final Result. Don’t worry if the code doesn’t make sense to you yet, or if it uses an unfamiliar syntax. We will be learning how to build this game step by step throughout this tutorial.
Try playing the game. You can also click on a button in the move list to go “back in time” and see what the board looked like just after that move was made.
Once you get a little familiar with the game, feel free to close that tab, as we’ll start from a simpler template in the next sections.
Prerequisites
We’ll assume some familiarity with HTML and JavaScript, but you should be able to follow along even if you haven’t used them before.
If you need a refresher on JavaScript, we recommend reading this guide. Note that we’re also using some features from ES6, a recent version of JavaScript. In this tutorial, we’re using arrow functions, classes, let, and const statements. You can use the Babel REPL to check what ES6 code compiles to.
How to Follow Along
There are two ways to complete this tutorial: you could either write the code right in the browser, or you could set up a local development environment on your machine. You can choose either option depending on what you feel comfortable with.
If You Prefer to Write Code in the Browser
This is the quickest way to get started!
First, open this starter code in a new tab. It should display an empty tic-tac-toe field. We will be editing that code during this tutorial.
You can now skip the next section about setting up a local development environment and head straight to the overview.
If You Prefer to Write Code in Your Editor
Alternatively, you can set up a project on your computer.
Note: this is completely optional and not required for this tutorial!
This is more work, but lets you work from the comfort of your editor.
If you want to do it, here are the steps to follow:
Make sure you have a recent version of Node.js installed.
Follow the installation instructions to create a new project.
npm install -g create-react-app
create-react-app my-app
Delete all files in the src/ folder of the new project (don’t delete the folder, just its contents).
cd my-app
rm -f src/*
Add a file named index.css in the src/ folder with this CSS code.
Add a file named index.js in the src/ folder with this JS code.
Add these three lines to the top of index.js in the src/ folder:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
Now if you run npm start in the project folder and open http://localhost:3000 in the browser, you should see an empty tic-tac-toe field.
We recommend following these instructions to configure syntax highlighting for your editor.
Help, I’m Stuck!
If you get stuck, check out the community support resources. In particular, Reactiflux chat is a great way to get quick help. If you don’t get a good answer anywhere, please file an issue, and we’ll help you out.
With this out of the way, let’s get started!
Overview
What is React?
React is a declarative, efficient, and flexible JavaScript library for building user interfaces.
React has a few different kinds of components, but we’ll start with React.Component subclasses:
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" />
We’ll get to the funny XML-like tags in a second. Your components tell React what you want to render – then React will efficiently update and render just the right components when your data changes.
Here, ShoppingList is a React component class, or React component type. A component takes in parameters, called props, and returns a hierarchy of views to display via the render method.
The render method returns a description of what you want to render, and then React takes that description and renders it to the screen. In particular, render returns a React element, which is a lightweight description of what to render. Most React developers use a special syntax called JSX which makes it easier to write these structures. The <div /> syntax is transformed at build time to React.createElement('div'). The example above is equivalent to:
return React.createElement('div', {className: 'shopping-list'},
  React.createElement('h1', /* ... h1 children ... */),
  React.createElement('ul', /* ... ul children ... */)
);
See full expanded version.
If you’re curious, createElement() is described in more detail in the API reference, but we won’t be using it directly in this tutorial. Instead, we will keep using JSX.
You can put any JavaScript expression within braces inside JSX. Each React element is a real JavaScript object that you can store in a variable or pass around your program.
The ShoppingList component only renders built-in DOM components, but you can compose custom React components just as easily, by writing <ShoppingList />. Each component is encapsulated so it can operate independently, which allows you to build complex UIs out of simple components.
Getting Started
Start with this example: Starter Code.
It contains the shell of what we’re building today. We’ve provided the styles so you only need to worry about the JavaScript.
In particular, we have three components:
Square
Board
Game
The Square component renders a single <button>, the Board renders 9 squares, and the Game component renders a board with some placeholders that we’ll fill in later. None of the components are interactive at this point.
Passing Data Through Props
Just to get our feet wet, let’s try passing some data from the Board component to the Square component.
In Board’s renderSquare method, change the code to pass a value prop to the Square:
class Board extends React.Component {
  renderSquare(i) {
    return <Square value={i} />;
  }
Then change Square’s render method to show that value by replacing {/* TODO */} with {this.props.value}:
class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {this.props.value}
      </button>
    );
  }
}
Before:
React Devtools
After: You should see a number in each square in the rendered output.
React Devtools
View the current code.
An Interactive Component
Let’s make the Square component fill in an “X” when you click it. Try changing the button tag returned in the render() function of the Square like this:
class Square extends React.Component {
  render() {
    return (
      <button className="square" onClick={() => alert('click')}>
        {this.props.value}
      </button>
    );
  }
}
If you click on a square now, you should get an alert in your browser.
This uses the new JavaScript arrow function syntax. Note that we’re passing a function as the onClick prop. Doing onClick={alert('click')} would alert immediately instead of when the button is clicked.
React components can have state by setting this.state in the constructor, which should be considered private to the component. Let’s store the current value of the square in state, and change it when the square is clicked.
First, add a constructor to the class to initialize the state:
class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null,
    };
  }

  render() {
    return (
      <button className="square" onClick={() => alert('click')}>
        {this.props.value}
      </button>
    );
  }
}
In JavaScript classes, you need to explicitly call super(); when defining the constructor of a subclass.
Now change the Square render method to display the value from the current state, and to toggle it on click:
Replace this.props.value with this.state.value inside the <button> tag.
Replace the () => alert() event handler with () => this.setState({value: 'X'}).
Now the <button> tag looks like this:
class Square extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: null,
    };
  }

  render() {
    return (
      <button className="square" onClick={() => this.setState({value: 'X'})}>
        {this.state.value}
      </button>
    );
  }
}
Whenever this.setState is called, an update to the component is scheduled, causing React to merge in the passed state update and rerender the component along with its descendants. When the component rerenders, this.state.value will be 'X' so you’ll see an X in the grid.
If you click on any square, an X should show up in it.
View the current code.
Developer Tools
The React Devtools extension for Chrome and Firefox lets you inspect a React component tree in your browser devtools.
React Devtools
It lets you inspect the props and state of any of the components in your tree.
After installing it, you can right-click any element on the page, click “Inspect” to open the developer tools, and the React tab will appear as the last tab to the right.
However, note there are a few extra steps to get it working with CodePen:
Log in or register and confirm your email (required to prevent spam).
Click the “Fork” button.
Click “Change View” and then choose “Debug mode”.
In the new tab that opens, the devtools should now have a React tab.
Lifting State Up
We now have the basic building blocks for a tic-tac-toe game. But right now, the state is encapsulated in each Square component. To make a fully-working game, we now need to check if one player has won the game, and alternate placing X and O in the squares. To check if someone has won, we’ll need to have the value of all 9 squares in one place, rather than split up across the Square components.
You might think that Board should just inquire what the current state of each Square is. Although it is technically possible to do this in React, it is discouraged because it tends to make code difficult to understand, more brittle, and harder to refactor.
Instead, the best solution here is to store this state in the Board component instead of in each Square – and the Board component can tell each Square what to display, like how we made each square display its index earlier.
When you want to aggregate data from multiple children or to have two child components communicate with each other, move the state upwards so that it lives in the parent component. The parent can then pass the state back down to the children via props, so that the child components are always in sync with each other and with the parent.
Pulling state upwards like this is common when refactoring React components, so let’s take this opportunity to try it out. Add a constructor to the Board and set its initial state to contain an array with 9 nulls, corresponding to the 9 squares:
class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
    };
  }

  renderSquare(i) {
    return <Square value={i} />;
  }

  render() {
    const status = 'Next player: X';

    return (
      <div>
        <div className="status">{status}</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>
    );
  }
}

We’ll fill it in later so that a board looks something like
我们填充这个类似于

[
  'O', null, 'X',
  'X', 'X', 'O',
  'O', null, null,
]

Board’s renderSquare method currently looks like this:
Board的renderSquare方法类似于

  renderSquare(i) {
    return <Square value={i} />;
  }

Modify it to pass a value prop to Square.
修改这个,然后传数据给Square

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

Now we need to change what happens when a square is clicked. The Board component now stores which squares are filled, which means we need some way for Square to update the state of Board. Since component state is considered private, we can’t update Board’s state directly from Square.
现在我们需要改变这个square点击之后的行为。Board组件现在保存了哪个square被填充,这个意味着我们需要一些方法来更新squre的状态,这个组件状态是私有的,我们不能直接更新。

The usual pattern here is pass down a function from Board to Square that gets called when the square is clicked. Change renderSquare in Board again so that it reads:

这个有用的模式是,顶一个函数,然后让Board来操作Square。

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

We split the returned element into multiple lines for readability, and added parens around it so that JavaScript doesn’t insert a semicolon after return and break our code.
我们把这个返回的元素到多行,添加父节点到JS,这个插入相同的,返回到我们的代码。

Now we’re passing down two props from Board to Square: value and onClick. The latter is a function that Square can call. Let’s make the following changes to Square:
我们现在通过两个props从Board到Square,value和onClick。
这个在后面是一个函数Square能调用。
- Replace this.state.value with this.props.value in Square’s render.
- Replace this.setState() with this.props.onClick() in Square’s render.
- Delete constructor definition from Square because it doesn’t have state anymore.

改变 this.state.vlue 替代为 this.props.value
改变this.setState() 替代为 this.props.onClick()
删除构造函数
After these changes, the whole Square component looks like this:
改完之后,类似于下面的代码

class Square extends React.Component {
  render() {
    return (
      <button className="square" onClick={() => this.props.onClick()}>
        {this.props.value}
      </button>
    );
  }
}

Now when the square is clicked, it calls the onClick function that was passed by Board. Let’s recap what happens here:
当squire被点击时,onClick函数传给Board

  1. The onClick prop on the built-in DOM component tells React to set up a click event listener.
  2. When the button is clicked, React will call the onClick event handler defined in Square’s render() method.
  3. This event handler calls this.props.onClick(). Square’s props were specified by the Board.
  4. Board passed onClick={() => this.handleClick(i)} to Square, so, when called, it runs this.handleClick(i) on the Board.
  5. We have not defined the handleClick() method on the Board yet, so the code crashes.

onClick是一个内置的函数
当button被点击了,React调用onClick函数
事件句柄调用this.props.onClick(),Square的props被调用
Board通过onClick给SQure,返回this.handleClick(i)
我们不能定义handleClick()方法,所有代码崩溃了

Note that DOM element’s onClick attribute has a special meaning to React, but we could have named Square’s onClick prop or Board’s handleClick method differently. It is, however, conventional in React apps to use on* names for the attributes and handle* for the handler methods.
注意DOM 元素的onClick属性是一个个别的含义对于React,但是我们有一个名字叫做squre的onClick属性,或者Board的handleClick方法不同。这个是在React app中 on*是对于任何的属性,handle* 是的句柄方法。
(这里说的就是一个命名规则,告诉你什么规则的名字表示什么)

Try clicking a square – you should get an error because we haven’t defined handleClick yet. Add it to the Board class.
点击 squre,你能得到一个错误,因为我们没有定义handleClick

class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
    };
  }

  handleClick(i) {
    const squares = this.state.squares.slice();
    squares[i] = 'X';
    this.setState({squares: squares});
  }

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

  render() {
    const status = 'Next player: X';

    return (
      <div>
        <div className="status">{status}</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>
    );
  }
}

We call .slice() to copy the squares array instead of mutating the existing array. Jump ahead a section to learn why immutability is important.
我们调用.slice()来复制squares 数组,你可以稍微一下为什么不变性的重要性。

Now you should be able to click in squares to fill them again, but the state is stored in the Board component instead of in each Square, which lets us continue building the game. Note how whenever Board’s state changes, the Square components rerender automatically.
现在你能够看到点击squares填充他们。但是states保存在Board组件中。让我们继续写这个游戏,注意无论Board的状态如何改变,square组件再次刷新是自动的。

Square no longer keeps its own state; it receives its value from its parent Board and informs its parent when it’s clicked. We call components like this controlled components.
Square不在保存他自己的状态,他接受一个值从父Board,然后通知他的父,当他被点击的时候,我们调用组件好像控制组件。

Why Immutability Is Important

为什么不变是重要的
In the previous code example, we suggest using the .slice() operator to copy the squares array prior to making changes and to prevent mutating the existing array.
Let’s talk about what this means and why it is an important concept to learn.
在之前的代码例子中,我们建议使用.slice()操作富复制square的数组来改变,我们讨论这个意思是为什么不变是重要的

There are generally two ways for changing data. The first method is to mutate the data by directly changing the values of a variable. The second method is to replace the data with a new copy of the object that also includes desired changes.
这里有两种方式来改变数据,一种方法是直接改变数据,地种方法是替换数据到一个新的copy

Data change with mutation
数据改变了

//直接改变数据的例子
var player = {score: 1, name: 'Jeff'};
player.score = 2;
// Now player is {score: 2, name: 'Jeff'}

Data change without mutation
不改变数据的例子

var player = {score: 1, name: 'Jeff'};

var newPlayer = Object.assign({}, player, {score: 2});
// Now player is unchanged, but newPlayer is {score: 2, name: 'Jeff'}
// player数据没有变会员,但newplayer 的score变为2

// Or if you are using object spread syntax proposal, you can write:
//或者你换一种写法,  ...player,score:2
//  javascript新的代码写起来很神奇

// var newPlayer = {...player, score: 2};

The end result is the same but by not mutating (or changing the underlying data) directly we now have an added benefit that can help us increase component and overall application performance.

这个最后的结果是相同,但是没有改变数据,这样的额好处是帮助我们提高组件和应用程序的性能。

Easier Undo/Redo and Time Travel
更好的撤销和redo的时间之旅?

Immutability also makes some complex features much easier to implement. For example, further in this tutorial we will implement time travel between different stages of the game. Avoiding data mutations lets us keep a reference to older versions of the data, and switch between them if we need to.
不变性让一些复杂点的特性容易执行。对于这个例子中,指南我们执行一个时间之旅在不同的状态中,忽略数据不不变性,我们报纸一个纸箱老的版本的数据。

Tracking Changes
跟踪改变

Determining if a mutated object has changed is complex because changes are made directly to the object. This then requires comparing the current object to a previous copy, traversing the entire object tree, and comparing each variable and value. This process can become increasingly complex.
决定一个突然变化的对象改变了这个是复杂的,因为改变是直接访问这个对象,这个需要对比当前值和之前的值。检查实体对象树,对比每个变量和值,这个处理变成非常复杂

Determining how an immutable object has changed is considerably easier. If the object being referenced is different from before, then the object has changed. That’s it.
确定一个不可改变的对象的改变非常简单,如果这个对象被应用不同于之前,这个对象改变了。

Determining When to Re-render in React
在React中山门时候再次渲染

The biggest benefit of immutability in React comes when you build simple pure components. Since immutable data can more easily determine if changes have been made, it also helps to determine when a component requires being re-rendered.
在React中不变的最大的优点是,当我们建立一个简单的纯净组件,当不变的数据容易决定如何改变,这个帮助组件确定什么时候再次刷新。

To learn more about shouldComponentUpdate() and how you can build pure components take a look at Optimizing Performance.
更多的学习,你可以了解shouldCompontUpdate()。纯净的组件看一下性能优化这里写链接内容

Functional Components

函数式组件
We’ve removed the constructor, and in fact, React supports a simpler syntax called functional components for component types like Square that only consist of a render method. Rather than define a class extending React.Component, simply write a function that takes props and returns what should be rendered.
我们已经移了构造函数,但是事实上,React支持简单的表达式调用功能性的组件,好像square只是包含一个渲染方法,必定一个类扩展React 组件,简单的写一个函数,获得props,然后返回如何被渲染。
Replace the whole Square class with this function:
替换整个square 类为这个函数

function Square(props) {
  return (
    <button className="square" onClick={props.onClick}>
      {props.value}
    </button>
  );
}

You’ll need to change this.props to props both times it appears. Many components in your apps will be able to be written as functional components: these components tend to be easier to write and React will optimize them more in the future.
你需要改变 this.props 为props。很多组件在你的陈旭中能够写函数式组件。这个组件趋势是简单可写,React能更好的优化他们
While we’re cleaning up the code, we also changed onClick={() => props.onClick()} to just onClick={props.onClick}, as passing the function down is enough for our example. Note that onClick={props.onClick()} would not work because it would call props.onClick immediately instead of passing it down.
当我们清理这些代码,我们改变了,onClick={() => props.onClick()} to just onClick={props.onClick}, 。 注意 onClick={props.onClick()}不能运行,因为这个调用了props.onClick 执行替代了传递这个值。

Taking Turns

An obvious defect in our game is that only X can play. Let’s fix that.
我们修正一下若干问题
Let’s default the first move to be by ‘X’. Modify our starting state in our Board constructor:
修改 state 在我们的Board的构造函数

class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
      xIsNext: true,
    };
  }

Each time we move we shall toggle xIsNext by flipping the boolean value and saving the state. Now update Board’s handleClick function to flip the value of xIsNext:
每次我们能把xIsNext作为一个布尔保存状态,更新Board的handleClick函数能够改变xIsNext值

  handleClick(i) {
    const squares = this.state.squares.slice();
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    //交替变化xIsNext
    this.setState({
      squares: squares,
      xIsNext: !this.state.xIsNext,
    });
  }

Now X and O take turns. Next, change the “status” text in Board’s render so that it also displays who is next:
X和O开始轮换交替,改变这个status的状态再Board中

  render() {
    const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');

    return (
      // the rest has not changed

After these changes you should have this Board component:
这些弄完之后,你可以看到如下的代码

class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
      xIsNext: true,
    };
  }

  handleClick(i) {
    const squares = this.state.squares.slice();
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      squares: squares,
      xIsNext: !this.state.xIsNext,
    });
  }

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

  render() {
    const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');

    return (
      <div>
        <div className="status">{status}</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>
    );
  }
}

Declaring a Winner

定义怎么算赢
Let’s show when a game is won. Add this helper function to the end of the file:
添加代码咯

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;
}

You can call it in Board’s render function to check if anyone has won the game and make the status text show “Winner: [X/O]” when someone wins.
你可以调用Board的render函数来检查,是否任何人赢了这个游戏,然后显示winnder [X/O]

Replace the status declaration in Board’s render with this code:
替换statues的申明在Board的render中

  render() {
    const winner = calculateWinner(this.state.squares);
    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

    return (
      // the rest has not changed

You can now change handleClick in Board to return early and ignore the click if someone has already won the game or if a square is already filled:
改代码~


handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}

Congratulations! You now have a working tic-tac-toe game. And now you know the basics of React. So you’re probably the real winner here.

恭喜,弄完了
//但是SB,我就跑不出来,codepan里面是babel代码我本地还不想支持这个

Storing a History

保存历史
Let’s make it possible to revisit old states of the board so we can see what it looked like after any of the previous moves. We’re already creating a new squares array each time a move is made, which means we can easily store the past board states simultaneously.
让我们尝试再次访问棋盘的老的状态,所以我们能看到和先前的任何移动,我们已经创建了一个squres数组每次移动到一个新状态,合格意味着我们简单的把老的状态保存
Let’s plan to store an object like this in state:
保存对象如下所示

history = [
  {
    squares: [
      null, null, null,
      null, null, null,
      null, null, null,
    ]
  },
  {
    squares: [
      null, null, null,
      null, 'X', null,
      null, null, null,
    ]
  },
  // ...
]

We’ll want the top-level Game component to be responsible for displaying the list of moves. So just as we pulled the state up before from Square into Board, let’s now pull it up again from Board into Game – so that we have all the information we need at the top level.
我们的game里面定义和扩展这个东东
First, set up the initial state for Game by adding a constructor to it:

class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      history: [{
        squares: Array(9).fill(null),
      }],
      xIsNext: true,
    };
  }

  render() {
    return (
      <div className="game">
        <div className="game-board">
          <Board />
        </div>
        <div className="game-info">
          <div>{/* status */}</div>
          <ol>{/* TODO */}</ol>
        </div>
      </div>
    );
  }
}

Then change Board so that it takes squares via props and has its own onClick prop specified by Game, like the transformation we made for Square earlier. You can pass the location of each square into the click handler so that we still know which square was clicked. Here is a list of steps you need to do:
做一下修正,

  • Delete the constructor in Board.
  • Replace this.state.squares[i] with this.props.squares[i] in Board’s renderSquare.
  • Replace this.handleClick(i) with this.props.onClick(i) in Board’s renderSquare.

删除构造函数
替换 this,state.squares[i] 为 this,props.squares[i]
替换 this.handleClick() 为this.props.onClick()

Now the whole Board component looks like this:
然后代码就看起来如下

class Board extends React.Component {
  handleClick(i) {
    const squares = this.state.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      squares: squares,
      xIsNext: !this.state.xIsNext,
    });
  }

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

  render() {
    const winner = calculateWinner(this.state.squares);
    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

    return (
      <div>
        <div className="status">{status}</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>
    );
  }
}

Game’s render should look at the most recent history entry and can take over calculating the game status:
游戏的渲染可以看到最近的历史,这个能够计算游戏的状态

  render() {
    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');
    }

    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>{/* TODO */}</ol>
        </div>
      </div>
    );
  }

Since Game is now rendering the status, we can delete

{status}
and the code calculating the status from the Board’s render function:
当游戏再次刷新状态,我们删除这个
{status}
这个代码计算status从棋盘的render函数

  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>
    );
  }

Next, we need to move the handleClick method implementation from Board to Game. You can cut it from the Board class, and paste it into the Game class.
接下去,我们需要移动Board的handleClick函数到Game中。

We also need to change it a little, since Game state is structured differently. Game’s handleClick can push a new entry onto the stack by concatenating the
new history entry to make a new history array.
我们小改一下。

  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({
      history: history.concat([{
        squares: squares,
      }]),
      xIsNext: !this.state.xIsNext,
    });
  }

At this point, Board only needs renderSquare and render; the state initialization and click handler should both live in Game.

快搞定了

Showing the Moves

显示移动

Let’s show the previous moves made in the game so far. We learned earlier that React elements are first-class JS objects and we can store them or pass them around. To render multiple items in React, we pass an array of React elements. The most common way to build that array is to map over your array of data. Let’s do that in the render method of Game:
我们需要显示一下之前的移动。

    const history = this.state.history;
    const current = history[history.length - 1];
    const winner = calculateWinner(current.squares);

    const moves = history.map((step, move) => {
      const desc = move ?
        'Go to move #' + move :
        'Go to game start';
      return (
        <li>
          <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>
    );
  }

For each step in the history, we create a list item

  • with a button inside it that has a click handler which we’ll implement shortly. With this code, you should see a list of the moves that have been made in the game, along with a warning that says:
    对于每一步的历史,我们创建了一个
  • 在每个button内,点击着handle,我们可以执行尽快,在这个代码中,我们可以看到我们移动的每一步
  • Warning: Each child in an array or iterator should have a unique “key” prop. Check the render method of “Game”.

    注意,每个数组的孩子或者生成器有一个唯一的key 属性

    Keys

    When you render a list of items, React always stores some info about each item in the list. If you render a component that has state, that state needs to be stored and regardless of how you implement your components, React stores a reference to the backing native views.
    当你渲染一个列表的时候,React总是保存这些信息对于每个item。如果你渲染这个组件的状态,这个状态需要保存,并且这个执行的组件,React保存这个指向到原生态的视图

    When you update that list, React needs to determine what has changed. You could’ve added, removed, rearranged, or updated items in the list.
    Imagine transitioning from

    当你更新这个列表,React需要确定这个视图是否变化,你不需要添加,删除,再排序或者更新这个数组。

    <li>Alexa: 7 tasks left</li>
    <li>Ben: 5 tasks left</li>

    to

    <li>Ben: 9 tasks left</li>
    <li>Claudia: 8 tasks left</li>
    <li>Alexa: 5 tasks left</li>

    To a human eye, it looks likely that Alexa and Ben swapped places and Claudia was added – but React is just a computer program and doesn’t know what you intended it to do. As a result, React asks you to specify a key property on each element in a list, a string to differentiate each component from its siblings. In this case, alexa, ben, claudia might be sensible keys; if the items correspond to objects in a database, the database ID is usually a good choice:

    对于人类的眼睛而言,这个看上去Alexa 和Ben移动了位置,Caludia添加了,但是React 作为计算机程序并非和你的认识一致。作为结果,React问你一个特别的key属性,对于每个元素在列表中,,在这个例子中,他们都不同

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

    key is a special property that’s reserved by React (along with ref, a more advanced feature). When an element is created, React pulls off the key property and stores the key directly on the returned element. Even though it may look like it is part of props, it cannot be referenced with this.props.key. React uses the key automatically while deciding which children to update; there is no way for a component to inquire about its own key.
    key作为一个特别的属性,是保留的,对于React。当一个元素被创建,REact把这个key元素推送过去,且通过这个key可以直接访问到元素。这个不能指向this.props.key . React使用key自动的,当确定这个孩子是否更新,这个没有别的方法对于组件而言来访问这个key

    When a list is rerendered, React takes each element in the new version and looks for one with a matching key in the previous list. When a key is added to the set, a component is created; when a key is removed, a component is destroyed. Keys tell React about the identity of each component, so that it can maintain the state across rerenders. If you change the key of a component, it will be completely destroyed and recreated with a new state.
    当列表再次被刷新,React对于每个元素的新的版本,看他们是否是先前的列表。当这个ke被添加到集合中,一个组件被创建,当这个key被移除,组件被销毁,keys告诉React这个定义的每个组件,然后这个维护状态通过再次渲染,如果你改变了组件的key,这个将要被完全销毁或者再次被创建由于一个新的值

    It’s strongly recommended that you assign proper keys whenever you build dynamic lists. If you don’t have an appropriate key handy, you may want to consider restructuring your data so that you do.
    强烈建议你标记属性key,无论你创建动态列表,如果你没有合适的key,你可以考虑结构化你的数据

    If you don’t specify any key, React will warn you and fall back to using the array index as a key – which is not the correct choice if you ever reorder elements in the list or add/remove items anywhere but the bottom of the list. Explicitly passing key={i} silences the warning but has the same problem so isn’t recommended in most cases.
    如果你没有任何的key,React将警告你,然后使用数组的index作为key,这个不是正确的做法 ,如果你重新排序元素,在这个列表添加或者删除元素任何时候。最好使用key={i} de slicences 告警,但是相同的问题,不推荐

    Component keys don’t need to be globally unique, only unique relative to the immediate siblings.
    组件的key,不需要全局唯一,只需要在相关的绑定唯一即可。

    Implementing Time Travel

    时间之旅
    For our move list, we already have a unique ID for each step: the number of the move when it happened. In the Game’s render method, add the key as

  • and the key warning should disappear:
    对于我们的移动列表,我们已经有唯一的代码对于每一步,所有的移动发生 时候,Game的渲染方法,添加key作为
  • 这个key的告警应该如下:
  •     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>
          );
        });

    Clicking any of the move buttons throws an error because jumpTo is undefined. Let’s add a new key to Game’s state to indicate which step we’re currently viewing.
    检查人和移动的button认出一个错误,因为jumpTo 没有定义,我们添加一个新的key到Game的 state 指向步骤当前的视图
    First, add stepNumber: 0 to the initial state in Game’s constructor:
    实现我们添加 stepNumber:0 初始化 state

    class Game extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          history: [{
            squares: Array(9).fill(null),
          }],
          stepNumber: 0,
          xIsNext: true,
        };
      }

    Next, we’ll define the jumpTo method in Game to update that state. We also want to update xIsNext. We set xIsNext to true if the index of the move number is an even number.
    Add a method called jumpTo to the Game class:

    然后我们添加jumpTo方法,来更新state,我们希望更新xIsNext

      handleClick(i) {
        // this method has not changed
      }
    
      jumpTo(step) {
        this.setState({
          stepNumber: step,
          xIsNext: (step % 2) === 0,
        });
      }
    
      render() {
        // this method has not changed
      }

    Then update stepNumber when a new move is made by adding stepNumber: history.length to the state update in Game’s handleClick. We’ll also update handleClick to be aware of stepNumber when reading the current board state so that you can go back in time then click in the board to create a new entry.:

    更新stepNumer当心的move产生,然后添加到Game handleClick

      handleClick(i) {
        const history = this.state.history.slice(0, this.state.stepNumber + 1);
        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({
          history: history.concat([{
            squares: squares
          }]),
          stepNumber: history.length,
          xIsNext: !this.state.xIsNext,
        });
      }

    Now you can modify Game’s render to read from that step in the history:

    继续修改代码

      render() {
        const history = this.state.history;
        const current = history[this.state.stepNumber];
        const winner = calculateWinner(current.squares);
    
        // the rest has not changed

    If you click any move button now, the board should immediately update to show what the game looked like at that time.

    Wrapping Up

    Now, you’ve made a tic-tac-toe game that:

    lets you play tic-tac-toe,

    indicates when one player has won the game,
    stores the history of moves during the game,
    allows players to jump back in time to see older versions of the game board.
    Nice work! We hope you now feel like you have a decent grasp on how React works.

    最终能玩了

    Check out the final result here: Final Result.
    If you have extra time or want to practice your new skills, here are some ideas for improvements you could make, listed in order of increasing difficulty:
    Display the location for each move in the format (col, row) in the move history list.
    Bold the currently selected item in the move list.
    Rewrite Board to use two loops to make the squares instead of hardcoding them.
    Add a toggle button that lets you sort the moves in either ascending or descending order.
    When someone wins, highlight the three squares that caused the win.
    Throughout this tutorial, we have touched on a number of React concepts including elements, components, props, and state. For a more in-depth explanation for each of these topics, check out the rest of the documentation. To learn more about defining components, check out the React.Component API reference.

    好了,就这样了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值