reactjs - 在返回中访问状态时反应组件未更新?
问题描述
在这里反应新手..
我正在关注官方 React 教程。以下代码是教程本身所示的工作版本:
class Square extends React.Component {
constructor(props, context) {
super(props, context);
}
render() {
return (
<button className="square"
onClick={() => this.props.onClick()}>
{this.props.value}
</button>
);
}
}
class Board extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
squares: Array(9).fill(null)
};
}
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>
);
}
handleClick(i) {
this.setState(
() => {
const squares = this.state.squares.slice();
squares[i] = 'X';
this.setState({squares: squares});
}
);
}
}
总而言之,Board
渲染 9Squares
并将回调函数传递给,Square
它会更新state
.Board
上面的代码工作得很好,当我点击任何一个Square
s 时,它的值会更新为X
.
但是,我按照教程犯了一个错误,实际上实现了render
和renderSquare
方法BoardComponent
如下:
renderSquare(i) {
return (
<Square
value={i}
onClick={() => this.handleClick(i)}
/>
);
}
render() {
const status = 'Next player: X';
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(this.state.squares[0])}
{this.renderSquare(this.state.squares[1])}
{this.renderSquare(this.state.squares[2])}
</div>
<div className="board-row">
{this.renderSquare(this.state.squares[3])}
{this.renderSquare(this.state.squares[4])}
{this.renderSquare(this.state.squares[5])}
</div>
<div className="board-row">
{this.renderSquare(this.state.squares[6])}
{this.renderSquare(this.state.squares[7])}
{this.renderSquare(this.state.squares[8])}
</div>
</div>
);
}
变化在于Board#renderSquare
方法以及如何从Board#render
.
此更改破坏了功能,Square
并且单击的 s 的值不会更新。
在我看来,这两种实现之间不应该有任何区别,但显然我遗漏了一些东西。为什么转向this.state.squares[]
方法会render
破坏功能?
解决方案
问题在renderSquare(i)
.
在this.renderSquare(this.state.squares[0])
,你传递null
给renderSquare
方法。
为了重新渲染您的组件,您需要定义一个与前一个不同的新状态,但是:
handleClick(i) {
this.setState(() => {
const squares = [...this.state.squares];
squares[i] = "X"; // <-- i is null
this.setState(prevState => {
const newState = { squares: squares };
console.log(prevState);
console.log(newState);
console.log(prevState === newState); // <-- true so no rerender.
return newState;
});
});
}
要修复它,state.squares
请在constructor
constructor(props, context) {
super(props, context);
this.state = {
squares: [...Array(9)].map((_, i) => i)
};
}
renderSquare(i) {
return <Square value={i} onClick={() => this.handleClick(i)} />;
}
在代码沙箱中查看此示例。
推荐阅读
- knex.js - 否定查询生成器中现有的 knex where 子句
- sql-server - 日志文件没有缩小
- spring - Spring Initializr 生成的 pom.xml 中的错误
- android - 给定特定位置(不是我们的位置)的分类搜索(如餐馆、医院等)
- emacs - 不可见文本的变量定义
- gatsby - 如何设置背景大小:包含在 Gatsbys 插件“gatsby-remark-images”中
- sql - SQL基于con将行提取到列中
- swift - 如何在金属上使用 Model I/O 框架加载 3d 资产 (.obj) 文件
- r - 按列分组并折叠所有其他没有 NA 的列
- azure - 我想在自动化帐户上创建一个运行手册,其中已经通过 arm 连接到它