React setState 立即生效的几种方式?

首先了解一个造成不能立即生效的原因,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 (
         <div>
            <button onClick={() => this.handleClick0()}>按钮0</button>
            <button onClick={() => this.handleClick1()}>按钮1</button>
            <button onClick={() => this.handleClick1()}>按钮2</button>
            <button id="btn4" onClick={() => this.handleClick1()}>
               按钮3
            </button>
         </div>
      );
   }
}

 

posted @ 2021-02-21 23:14  程序員劝退师  阅读(6907)  评论(0编辑  收藏  举报