您的位置:首页 > Web前端 > React

React 实现井字棋游戏 (tic-tac-toe) 教程 (6) <译自官方文档>

2017-11-06 16:46 806 查看
React 实现井字棋游戏 (tic-tac-toe) 教程 (1) <译自官方文档>

React 实现井字棋游戏 (tic-tac-toe) 教程 (2) <译自官方文档>

React 实现井字棋游戏 (tic-tac-toe) 教程 (3) <译自官方文档>

React 实现井字棋游戏 (tic-tac-toe) 教程 (4) <译自官方文档>

React 实现井字棋游戏 (tic-tac-toe) 教程 (5) <译自官方文档>

KEYS

当你渲染列表中的项目时,React 总会储存各个项目的相关信息。如果你渲染一个有状态 (state) 的组件,React 需要储存状态。不论你如何实现你的组件,React 总会存储对之前状态的引用。

当你更新列表的时候,React 需要判断到底是哪些内容被更新:你可能添加、删除、重排列,或者更新了项目。

比如,从这样:

code

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


变成这样:

code

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


在人眼看来,这只不过就是把 Alexa 和 Ben 调换了下位置,又加上了 Claudia。但 React 只是个程序,它不懂你想要怎么干。因而, React 要求,必须为列表中的每个元素都指定一个 key 属性,即一个字符串,用来区分各个组件。在本案例中,
alexa
ben
,
claudia
就可以是很合适的 key。如果项目对应于数据库中的对象,那数据库 ID 通常也是一个好的选择:

code

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


key
是 React 保留的特殊属性(和
ref
一样,那个更高级)。当元素被创建,React 拉取
key
属性,并将其直接储存到返回的元素上。尽管它看起来像是 props 的一部分,但其实并不能通过
this.props.key
来引用。在判断哪个子组件应该被更新时,React 自动使用 key。组件自己是没办法查询自己的 key 的。

当列表被重新渲染,React 会在新的版本提取每个元素,寻找里面有没有能和之前列表相匹配上的 key。当一个 key 被添加到集合中时,一个组件实例会被创建;当一个 key 被删除时,一个组件实例会被销毁。React 通过 key 来识别每个组件的身份,组件由此得以在重新渲染的过程中保持状态(state)。如果改变了组件的 key,则该组件实例将被销毁,再重创建一个新的组件实例。这样,原来的状态无法继承,而是创建新的状态。

我们强烈建议,只要你建立动态列表,你应该设置合适的 key。如果你没有合适的 key,或许你该考虑一下重构你的数据,来得到合适的 key。

如果你没有指定任何 key,React 将会发出警告,并回头使用数组的 index 作为 key。但这么干也是不对的,因为当你重新排列表单中的元素,或者 增/删 非列表底部的项目时,就会出问题。明确地传入
key={i}
虽然会让警告消失,但还是存在相同的问题。所以,大多数情况下,我们也不推荐这么做。

组件的 key 不需要再全局环境下保持唯一,只需要在兄弟组件间保持唯一就可以了。

实现穿越功能

记录历史步骤的列表里头,每一个步骤都有了一个唯一的 ID,即这一步走的时候。在 Game 组件的
render
方法里,这么添加 key:
<li key={move}>
,刚才的警告就会消失。

code

const moves = history.map((step, move) => {
const desc = move ?
'Move #' + move :
'Game start';
return (
<li key={move}>
<a href="#" onClick={() => this.jumpTo(move)}>{desc}</a>
</li>
);
});


查看最新的代码

点击里面的步骤,会报错。因为
jumpTo
方法还没定义。我们在 Game 组件的 state 里面新添加一条,用来指示当前的我们正在查看的步骤。

首先,在 Game 组件的
constructor
中,添加初始状态:
stepNumber: 0


code

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


下一步,在 Game 组件中,定义
jumpTo
方法,用以更新那条状态。
xIsNext
同样需要更新,如果一步棋的序号数是偶数,我们就把
xIsNext
的值设为 true。

向Game的类增加
jumpTo
方法:

code

handleClick(i) {
// 本方法不做改动
}

jumpTo(step) {
this.setState({
stepNumber: step,
xIsNext: (step % 2) ? false : true,
});
}

render() {
// 本方法不做改动
}


为了实现在新走一步棋时,
stepNumber
可以更新的功能,我们在 Game 组件
handleClick
中的状态更新语句里添加
stepNumber: history.length


code

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


现在,你就可以修改 Game 组件的
render
函数,以实现从历史记录中读取步骤了。

code

render() {
const history = this.state.history;
const current = history[this.state.stepNumber];
const winner = calculateWinner(current.squares);

// the rest has not changed


查看最新的代码

现在你再点击列表里的步骤,棋盘应该就能立即更新,穿越回当时的那一步了。

你可能还想要更新
handleClick
,以便在读取当前 board 状态的时候,获取
stepNumber
。这样就能在穿越回去后,又点击棋盘时,创建新的步骤记录。(提示:最简单的办法,就是在
handleClick
的一开始,用
.slice()
把历史记录额外的元素切下来。)

圆满完成

现在,你的井字棋已经实现了如下功能:

* 你可以玩井字棋游戏;

* 当有玩家获胜时,宣布结果;

* 存储棋局的历史步骤记录;

* 允许玩家穿越回之前,查看当时棋盘的格局。

干得漂亮!我们希望你已经觉得自己对 React 有了较为深入的把握。

点击查看最终的代码

如果你还有时间,想要练习新学到的技能,这里列出了一些难度提升的改进:

记录落子的位置时,以“(1,3)”的格式显示,而不仅仅只显示“6”;

在历史步骤记录表单中,对当前选中的步骤加粗显示;

重写 Board 组件,使用两个循环来构造小方格,而非直接写死(hardcode)。

添加切换按钮,实现步骤排列的升序排列或降序排列。

有人胜出的时候,将那一排胜利的小方格高亮显示。

通过本教程,我们接触了一些 React 的概念,包括:元素 elements, 组件 components, props 和 状态 state。想要进一步深入了解这些话题,请查看其它文档。想要进一步学习如何定义组件,点击
React.Component
API引用文档


译者注

这个仓库是我实现的tic-tac-toe,在文档基础上添加了一些扩展功能:

增加和棋判断;

以直角坐标系的形式(x,y)记录落子位置;

高亮显示胜负手,使结局一目了然;

实现了通过按钮,切换步骤历史记录的正序、逆序排列;

添加了重置按钮,一键重新开始;

高亮显示历史记录列表中的当前选中项;

添加了 AI 功能,可人机对弈,亦可赛艇帮人决策。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  react 教程 文档
相关文章推荐