即使状态发生变化,反应也不会使组件发生变化
正如我在反应主页here中遵循教程一样。我想修改x-o游戏代码以在游戏中前进和后退。我包含下面的代码。即使状态发生变化,反应也不会使组件发生变化
历史被记录在历史列表中,pos是列表上当前选择的索引。你可以看到我有三个按钮:复位,向上,向下。当您按Reset时,我重置状态。当你按下时,我增加pos。当你按下时,我减少pos。我也显示pos来检查。
问题是pos正在更新,但组件没有重新渲染。为便于使用我包括heroku here
我在这里失踪了什么?
import React, { Component } from 'react';
import './App.css';
function Square(props){
return (
<div className="square" onClick={() => props.onClick()}>
{props.value}
</div>
);
}
function calculateWinner(squares){
const winners = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 4, 8],
[2, 4, 6],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8]
];
for(let i = 0; i < winners.length; i++){
const [a, b, c] = winners[i];
if(squares[a] && squares[b] === squares[a] && squares[c] === squares[a]){
return squares[a];
}
}
return null;
}
class Board extends Component{
constructor() {
super();
this.state = {
history: [Array(9).fill(null)],
pos : 0,
xIsNext: true
}
}
handleClick(i){
const current = this.state.history[this.state.pos];
if (current[i] || calculateWinner(current)) {
} else {
const history = this.state.history.slice();
const squares = history[this.state.pos].slice();
squares[i] = this.state.xIsNext ? "X" : "O";
history[this.state.pos + 1] = squares;
this.setState({
history: history,
pos: this.state.pos + 1,
xIsNext: !this.state.xIsNext
});
}
}
clickReset(){
this.setState(
{
history: [Array(9).fill(null)],
pos : 0,
xIsNext: true
}
);
}
clickUp(){
let pos = this.state.pos;
if(pos < this.state.history.length) {
pos += 1;
this.setState(
{
pos: pos,
xIsNext: !this.state.xIsNext
}
);
}
}
clickDown(){
let pos = this.state.pos;
if(pos > 0) {
pos -= 1;
this.setState(
{
pos: pos,
xIsNext: !this.state.xIsNext
}
);
}
}
renderSquare(i){
let current = this.state.history[this.state.pos];
return (
<Square value={current[i]} onClick={() => this.handleClick(i)}/>
)
}
render() {
let status ;
const pos = this.state.pos;
const current = this.state.history[pos];
const winnerCal = calculateWinner(current);
if (winnerCal){
status = "Winner : " + winnerCal;
} else {
status = "Next Play : " + (this.state.xIsNext ? "X" : "O");
}
return (
<div className="col">
<div className="row justify-content-center">
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="w-100"></div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="w-100"></div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
<div className="row justify-content-center">
{status} pos: {pos}
</div>
<div className="row-fluid">
<button type="button" className="col-md-4 btn btn-warning" onClick={() => this.clickReset()}>Reset</button>
<button type="button" className="col-md-4 btn btn-danger" onClick={() => this.clickUp()}>up</button>
<button type="button" className="col-md-4 btn btn-info" onClick={() => this.clickDown()}>down</button>
</div>
</div>
)
}
}
class App extends Component {
renderHeader(){
return (
<div className="row justify-content-center">
<div className="col"></div>
<div className="col">
<h3 className="row justify-content-center"> Lets build a xo game </h3>
</div>
<div className="col"></div>
</div>
)
}
renderBoard(){
return (
<div className="row">
<div className="col"></div>
<Board className="col"/>
<div className="col"></div>
</div>
)
}
render() {
return (
<div className="container">
{this.renderHeader()}
{this.renderBoard()}
</div>
);
}
}
export default App;
编辑:
在handleClick()改变
const squares = history[this.state.pos]
..
history[history.length] = squares;
到
const squares = history[this.state.pos].slice();
..
history[this.state.pos + 1] = squares;
你的做法是最有可能运作良好。问题是你的历史被改写
const squares = history[this.state.pos];
squares[i] = this.state.xIsNext ? "X" : "O";
history[history.length] = squares;
导致历史[history.length]引用同一个对象作为历史[history.length - 1]等降至历史[0]
尝试使用
const squares = history[this.state.pos].slice();
解决了问题,但为什么应该处理ClickClick()链接点击个别方块会影响应呈现的内容。当我点击“向上”或“向下”时,要更清楚一点,如果你可以说slice()在那里的重要性,那么handleClick()的依赖关系是一个onClick方法() – StarLord
。这将非常有用 – StarLord
您在handleClick()处更新了组件状态,并且状态更改触发了新的呈现。当你调用setState时,你改变整个棋盘的状态(根据this.state.history渲染)。 这个问题是由于修改了最初得到的同一个方格数组而导致的,它使历史集合中的所有数组都引用了同一个实例。为了让每个新的历史事件成为前一步的副本,我使用了slice来获得浅拷贝 – Igor
我在渲染函数中放置了一个断点,每次单击按钮时都会调用它。 – paqash
确定将问题更改为更准确的问题 – StarLord