当我们有了前面知识的铺垫,就很容易理解this.setState的工作流程。

流程概览

可以看到,this.setState内会调用this.updater.enqueueSetState方法。

  1. Component.prototype.setState = function (partialState, callback) {
  2. if (!(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null)) {
  3. {
  4. throw Error( "setState(...): takes an object of state variables to update or a function which returns an object of state variables." );
  5. }
  6. }
  7. this.updater.enqueueSetState(this, partialState, callback, 'setState');
  8. };

你可以在这里this.setState - 图1 (opens new window)看到这段代码

enqueueSetState方法中就是我们熟悉的从创建update调度update的流程了。

  1. enqueueSetState(inst, payload, callback) {
  2. // 通过组件实例获取对应fiber
  3. const fiber = getInstance(inst);
  4. const eventTime = requestEventTime();
  5. const suspenseConfig = requestCurrentSuspenseConfig();
  6. // 获取优先级
  7. const lane = requestUpdateLane(fiber, suspenseConfig);
  8. // 创建update
  9. const update = createUpdate(eventTime, lane, suspenseConfig);
  10. update.payload = payload;
  11. // 赋值回调函数
  12. if (callback !== undefined && callback !== null) {
  13. update.callback = callback;
  14. }
  15. // 将update插入updateQueue
  16. enqueueUpdate(fiber, update);
  17. // 调度update
  18. scheduleUpdateOnFiber(fiber, lane, eventTime);
  19. }

你可以在这里this.setState - 图2 (opens new window)看到enqueueSetState代码

这里值得注意的是对于ClassComponentupdate.payloadthis.setState的第一个传参(即要改变的state)。

this.forceUpdate

this.updater上,除了enqueueSetState外,还存在enqueueForceUpdate,当我们调用this.forceUpdate时会调用他。

可以看到,除了赋值update.tag = ForceUpdate;以及没有payload外,其他逻辑与this.setState一致。

  1. enqueueForceUpdate(inst, callback) {
  2. const fiber = getInstance(inst);
  3. const eventTime = requestEventTime();
  4. const suspenseConfig = requestCurrentSuspenseConfig();
  5. const lane = requestUpdateLane(fiber, suspenseConfig);
  6. const update = createUpdate(eventTime, lane, suspenseConfig);
  7. // 赋值tag为ForceUpdate
  8. update.tag = ForceUpdate;
  9. if (callback !== undefined && callback !== null) {
  10. update.callback = callback;
  11. }
  12. enqueueUpdate(fiber, update);
  13. scheduleUpdateOnFiber(fiber, lane, eventTime);
  14. },
  15. };

你可以在这里this.setState - 图3 (opens new window)看到enqueueForceUpdate代码

那么赋值update.tag = ForceUpdate;有何作用呢?

在判断ClassComponent是否需要更新时有两个条件需要满足:

  1. const shouldUpdate =
  2. checkHasForceUpdateAfterProcessing() ||
  3. checkShouldComponentUpdate(
  4. workInProgress,
  5. ctor,
  6. oldProps,
  7. newProps,
  8. oldState,
  9. newState,
  10. nextContext,
  11. );

你可以在这里this.setState - 图4 (opens new window)看到这段代码

  • checkHasForceUpdateAfterProcessing:内部会判断本次更新的Update是否为ForceUpdate。即如果本次更新的Update中存在tagForceUpdate,则返回true

  • checkShouldComponentUpdate:内部会调用shouldComponentUpdate方法。以及当该ClassComponentPureComponent时会浅比较stateprops

你可以在这里this.setState - 图5 (opens new window)看到checkShouldComponentUpdate代码

所以,当某次更新含有tagForceUpdateUpdate,那么当前ClassComponent不会受其他性能优化手段shouldComponentUpdate|PureComponent)影响,一定会更新。

总结

至此,我们学习完了HostRoot | ClassComponent所使用的Update的更新流程。

在下一章我们会学习另一种数据结构的Update —— 用于HooksUpdate