React setState机制

2019-02-21 19:57 热度: 514 我说呢

setState是react的一个常常用的方法了,顾名思义,是用于更新state的,继而更新组件。但是里面也有一些坑对于新手,举个例子:

lizi.jpg
class Example extends React.Component {
  constructor() {
    super();
    this.state = {
      val: 0
    };
  }
  
  componentDidMount() {
    this.setState({val: this.state.val + 1});
    console.log(this.state.val);    // 第 1 次 log

    this.setState({val: this.state.val + 1});
    console.log(this.state.val);    // 第 2 次 log

    setTimeout(() => {
      this.setState({val: this.state.val + 1});
      console.log(this.state.val);  // 第 3 次 log

      this.setState({val: this.state.val + 1});
      console.log(this.state.val);  // 第 4 次 log
    }, 0);
  }

  render() {
    return null;
  }
};

答案是: 0 0 2 3

怎么样,脑瓜子嗡嗡的吧?(暗笑.gif)

下面解释下:

setState处理机制

// react/lib/ReactComponent.js

ReactComponent.prototype.setState = function (partialState, callback) {
    this.updater.enqueueSetState(this, partialState);
    if (callback) {
        this.updater.enqueueCallback(this, callback, 'setState');
    }
}
// react-dom/lib/ReactUpdateQueue.js

var ReactUpdateQueue = {
    enqueueSetState: function (publicInstance, partialState) {
        
        // 获取React Component的内部实例,在comp._reactInternalInstance属性上存储着
        var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');

        if (!internalInstance) {
          return;
        }

        // 将state插入到内部component实例的state队列中
        var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
        queue.push(partialState);

        // 处理更新
        enqueueUpdate(internalInstance);
    }
}

function enqueueUpdate(internalInstance) {
  ReactUpdates.enqueueUpdate(internalInstance);
}
// ReactUpdates

function enqueueUpdate(component) {
    if (!batchingStrategy.isBatchingUpdates) {
        batchingStrategy.batchedUpdates(enqueueUpdate, component);
        return;
    }

    dirtyComponents.push(component);
}

下面大体文字解释下:

在React中,如果是由React引发的事件处理(比如通过onClick引发的事件处理),调用setState不会同步更新this.state,除此之外的setState调用会同步执行this.state。所谓'除此之外',指的是绕过React通过addEventListener直接添加的事件处理函数,还有通过setTimeout/setInterval产生的异步调用。

原因:在React的setState函数实现中,会根据一个变量isBatchingUpdates判断是直接更新this.state还是放到队列中回头再说,而isBatchingUpdates默认是false,也就表示setState会同步更新this.state,但是,有一个函数batchedUpdates,这个函数会把isBatchingUpdates修改为true,而当React在调用事件处理函数之前就会调用这个batchedUpdates,造成的后果,就是由React控制的事件处理过程setState不会同步更新this.state。

另外还有关于 Transaction源码部分就不写了,直接看下面的参考文献就行了。

参考文献: 深入 setState 机制

查看评论 (0条)

添加评论