首先了解一个造成不能立即生效的原因,setState异步的原因是因为react的监听事件为合成事件,state执行过程中会经历一个生命周期函数,执行多个setState会被合并,提升性能,下面几种方式可以避免我们的问题:

shouleComponentUpdate

componentWillUpdate

render

componentDidUpdate

setState合适同步何时异步?

由React控制的事件处理程序,以及生命周期函数调用setState不会同步更新state 。

React控制之外的事件中调用setState是同步更新的。比如原生js绑定的事件,setTimeout/setInterval等。

this.setState({ count: this.state.count + 1 });

this.setState({ count: this.state.count + 1 });

this.setState({ count: this.state.count + 1 });

// 执行后结果相当于

const count = this.state.count;

this.setState({ count: count + 1 });

this.setState({ count: count + 1 });

this.setState({ count: count + 1 });

1、传递函数()=>{return state},react提供的参数props保证每次都拿到最新的

// 第一个函数调用更新state,第二个函数是更新完之后的回调。

this.setState((prevState, props) => {

return {

age: prevState.count + 1,

};

// 获取state

console.log(this.state); // 1

});

2、设置setTimeout、setInterval,和事件玄幻有关系

setTimeout(fn,0)的含义是,指定某个任务在主线程最早可得的空闲时间执行,也就是说,尽可能早得执行。它在"任务队列"的尾部添加一个事件,因此要等到同步任务和"任务队列"现有的事件都处理完,才会得到执行。

setTimeout(() => {

this.setState(prevState => {

return {

age: prevState.count + 1,

};

});

// 获取state

console.log(this.state); // 1

}, 0);

3、设置js原生监听事件addEventListener

原生事件的调用栈就比较简单了,因为没有走合成事件的那一大堆,直接触发click事件,到 requestWork ,在requestWork里由于 expirationTime === Sync 的原因,直接走了 performSyncWork 去更新,并不像合成事件或钩子函数中被return,所以当你在原生事件中setState后,能同步拿到更新后的state值。

handleClick3 = () => {

this.setState({ count: this.state.count + 1 });

// 某些条件可能获取不到最新的值

console.log(this.state);

};

componentDidMount() {

document.body.addEventListener('btn4', this.handleClick3, false);

}

详细代码如下:

class Demo extends React.Component {

state = {

count: 0,

};

handleClick0 = () => {

this.setState({ count: this.state.count + 1 });

this.setState({ count: this.state.count + 1 });

this.setState({ count: this.state.count + 1 });

// 某些条件可能获取不到最新的值

console.log(this.state);

};

// 1、把对象改为回调函数

handleClick1 = () => {

this.setState(prevState => {

return {

age: prevState.count + 1,

};

});

// 获取state

console.log(this.state); // 1

};

// 2、设置setTimeout,setInterval

handleClick2 = () => {

setTimeout(() => {

this.setState(prevState => {

return {

age: prevState.count + 1,

};

});

// 获取state

console.log(this.state); // 1

}, 0);

};

// 3、设置原生监听事件,不同调用react的一些生命周期,直接触发onclick

handleClick3 = () => {

this.setState({ count: this.state.count + 1 });

// 某些条件可能获取不到最新的值

console.log(this.state);

};

componentDidMount() {

document.body.addEventListener('btn4', this.handleClick3, false);

}

render() {

return (

);

}

}