为什么多次调用setState()时状态无法正确更新

时间:2017-07-03 02:16:23

标签: javascript reactjs

单击按钮时,应通过以下功能将文本“第二条消息”和“第三条消息”添加到状态:

root@swarm-master-784816DA-0:~# docker run -d -p 80:80 yeasy/simple-web
0226e9ab3cadf20701f64c02f1f4a42f5fd57fd297722f268db47db1b124ab5c
root@swarm-master-784816DA-0:~# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
0226e9ab3cad        yeasy/simple-web    "/bin/sh -c 'pytho..."   6 seconds ago       Up 5 seconds        10.0.0.5:80->80/tcp   swarm-agent-784816DA000001/stupefied_snyder

但其中只有一人正在开火。

我创建了一个显示问题的简单代码段。

class Button extends React.Component {

    constructor(props) {
        super(props);
        this.addMessage = this.addMessage.bind(this);
    }

    addMessage() {
        this.props.addMessage('second message'); // This is ignored
        this.props.addMessage('third message');  // Only this message is added
    }

    render() {
        return(
            <button onClick={this.addMessage}>Add text</button>
        )
    }
}
class Button extends React.Component {

	constructor(props) {
		super(props);
		this.addMessage = this.addMessage.bind(this);
	}
	
	addMessage() {
		this.props.addMessage('second message'); // This is ignored
		this.props.addMessage('third message');	 // Only this message is added
	}
	
	render() {
		return(
			<button onClick={this.addMessage}>Add text</button>
		)
	}

}

class Messages extends React.Component {

	constructor(props) {
		super(props);
	}
	
	render() {
		return(
			<p>{this.props.message}</p>
		)
	}

}

class App extends React.Component {
	
	constructor(props) {
		super(props);
		this.state = {
			messages: [{
				text: 'first message'
			}]
		}
		this.addMessage = this.addMessage.bind(this);
	}
	
	addMessage(message) {
		let messages = this.state.messages.slice();
		messages.push({text:message});
		this.setState({messages: messages});
	}
	
	render() {
		let messages = [];
		this.state.messages.forEach((message) => {
			messages.push(<Messages message={message.text}></Messages>);
		});
		return(
			<div>
				{messages}
				<Button addMessage={this.addMessage} />
			</div>
		)
	}
}

ReactDOM.render(
	<App />,
	document.getElementById('root')
);

提前致谢!

1 个答案:

答案 0 :(得分:3)

状态更新可能是异步的

引自reactjs docs about state updates

  

React可以将多个setState()个调用批处理为一个更新   性能

     

由于this.propsthis.state可以异步更新,你   不应该依赖他们的价值来计算下一个州

您对addMessage()的第二次通话使用this.state来设置新状态。但是因为setState()是异步的,我的状态还没有更新,导致你的第二次调用覆盖了你的第一个:

addMessage(message) {

    // here you access this.state which hasn't been updated yet in your second call
    let messages = this.state.messages.slice();

    messages.push({text: message});
    this.setState({messages: messages});
}
  

要修复它,请使用接受函数的第二种setState()形式   而不是一个对象。该功能将接收先前的状态   作为第一个参数,以及应用更新时的道具   作为第二个论点:

使用传递前一状态的箭头函数,包括先前调用setState()的更改以计算新状态。这将解决您的问题。

使用es6传播语法:

this.setState((prevState, props) => ({
    messages: [...prevState.messages, {text: message}]
}));

使用slice()

this.setState((prevState, props) => {
    let messages = prevState.messages.slice();
    messages.push({text:message});
    return {messages};
});