在这里与新手联系。
我正在关注Official React Tutorial。以下代码是本教程本身所示的工作版本:
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
呈现9 Squares
并将回调函数传递给Square
,后者会更新state
的{{1}}。
上面的代码运行良好,当我单击任何Board
时,其值将更新为Square
。
但是,我在学习本教程后犯了一个错误,并实际上在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
移至this.state.squares[]
方法会破坏功能?
答案 0 :(得分:0)
问题在于任何this.state.squares[n]
可以是null
或X
。
在您的代码中,您可以这样做:
renderSquare(i) {
return (
<Square
value={i}
onClick={() => this.handleClick(i)}
/>
);
}
{this.renderSquare(this.state.squares[n])}
您将值(而不是索引)传递给renderSquare
。 i
中的renderSquare
是null
或X
。意味着handleClick
不知道要更改什么,因为它需要索引。
答案 1 :(得分:0)
问题出在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)} />;
}
在codesandbox上查看此示例。