javascript - 为什么多次调用 setState() 时状态不能正确更新

标签 javascript reactjs

点击按钮时,应该通过这些函数将文本“第二条消息”和“第三条消息”添加到状态:

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')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>

<div id="root"></div>

提前致谢!

最佳答案

状态更新可能是异步的

引自reactjs docs about state updates :

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next 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});
}

To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:

使用一个箭头函数来传递先前的状态,包括对 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};
});

关于javascript - 为什么多次调用 setState() 时状态不能正确更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44876902/

相关文章:

javascript - Jison 类谷歌解析器

reactjs - 使用 react-router-dom 在组件基础上键入 location.state 属性

javascript - 在 React 中,componentDidMount 何时会为不直接呈现标记的组件触发?

node.js - 从父文件夹导入时,类型错误 : Super expression must either be null or a function, 未定义

javascript - Discord.js 机器人错误,控制台 : DiscordAPIError: Cannot send an empty message

javascript - jQuery 检查复选框是否被选中,然后将值添加到输入字段

javascript - 为什么 event.preventDefault() 无法取消 Angular js 中的 $routeChangeStart 事件

javascript - 网站的图库软件,可根据高度调整大小,单击图像即可导航

javascript - 将字符串数组映射为对象属性

css - 如何在 JS 中使用 css 来实现嵌套悬停样式、Material UI