微信截图_20210411132701.png

合成事件

在 React 自己的生命周期事件和合成事件中,可以拿到 isBatchingUpdates 的控制权,将状态放进队列,控制执行节奏。而在外部的原生事件中,并没有外层的封装与拦截,无法更新 isBatchingUpdates 的状态为 true。这就造成 isBatchingUpdates 的状态只会为 false,且立即执行。所以在 addEventListener 、setTimeout、setInterval 这些原生事件中都会同步更新。

CgpVE1_YUqKAA-jWAACt3Mh2xk8536.png

  • React 给 document 挂上事件监听
  • DOM 事件触发后冒泡到 document
  • React 找到对应的组件,造出一个合成事件出来
  • 并按组件树模拟一遍事件冒泡

React 17后事件委托挂载到 DOM 容器上,即 ReactDom.Render 所调用的节点上

异步的动机和原理

为什么要出现异步?
从生命周期的角度出发,避免频繁的 re-render(重渲染)
Ciqc1F-uMeSAYK6FAABN0Vwnq5M814.png

setState 工作流

SetState.png

  1. ReactComponent.prototype.setState = function (partialState, callback) {
  2. // 将setState事务放进队列中
  3. this.updater.enqueueSetState(this, partialState);
  4. if (callback) {
  5. this.updater.enqueueCallback(this, callback, 'setState');
  6. }
  7. };
  8. enqueueSetState: function (publicInstance, partialState) {
  9. // 根据 this 拿到对应的组件实例
  10. var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');
  11. // 这个 queue 对应的就是一个组件实例的将要更新的 state 数组
  12. var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
  13. queue.push(partialState);
  14. // enqueueUpdate 用来处理当前的组件实例
  15. enqueueUpdate(internalInstance);
  16. }
  17. function enqueueUpdate(component) {
  18. ensureInjected();
  19. // 注意这一句是问题的关键,isBatchingUpdates标识着当前是否处于批量创建/更新组件的阶段
  20. if (!batchingStrategy.isBatchingUpdates) {
  21. // 若当前没有处于批量创建/更新组件的阶段,则立即更新组件
  22. batchingStrategy.batchedUpdates(enqueueUpdate, component);
  23. return;
  24. }
  25. // 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”
  26. dirtyComponents.push(component);
  27. if (component._updateBatchNumber == null) {
  28. component._updateBatchNumber = updateBatchNumber + 1;
  29. }
  30. }

参考资料

  1. 11 | setState 到底是同步的,还是异步的?
  2. How Does setState Know What to Do?
  3. 揭密React setState
  4. 06 | setState 是同步更新还是异步更新?