react 内部原理
内部原理
JSX 语法、内部数据结构、协调器对比算法、算法优化的假设条件、setState 更新、合成事件、Fiber
JSX 语法
内部数据结构
- React Element
 React.createElement 的结果1 
 2
 3
 4
 5
 6
 7
 8ReactElement { 
 _owner: null, // parent internal instance
 _store: Object {},
 key: null,
 props: Object {},
 ref: null,
 type: Function|string
 }
- Public Instance
 component 组件实例 this1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24Component { 
 _reactInternalInstance: ReactCompositeComponentWrapper,
 context: Object,
 props: Object,
 refs: Object,
 state: Object,
 updater: Object,
 __proto__: ReactComponent {
 constructor: Function,
 componentWillMount: Function,
 render: Function,
 componentDidMount: Function,
 componentWillReceiveProps: Function,
 shouldComponentUpdate: Function,
 componentWillUpdate: Function,
 componentDidUpdate: Function,
 componentWillUnmount: Function,
 __proto__: {
 constructor: Function,
 forceUpdate: Function,
 setState: (partialState, callback)
 }
 }
 }
- Internal Instance
 组件的额外信息1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42ReactCompositeComponent { 
 _compositeType: Impure|Pure|StatelessFunctional,
 _context: Object,
 _currentElement: ReactElement,
 _instance: ***Public Instance***,
 _isOwnerNecessary: false,
 _mountImage: null,
 _mountIndex: 0,
 _mountOrder: 2,
 _pendingCallbacks: null,
 _pendingElement: null,
 _pendingStateQueue: null,
 _renderedComponent: ***ReactDOMComponent***,
 _rootNodeID: ".0",
 _topLevelWrapper: ***ReactCompositeComponentWrapper***,
 _warnedAboutRefsInRender: false
 }
 ReactCompositeComponent.prototype {
 _checkPropTypes: Function,
 _instantiateReactComponent: Function,
 _maskContext: Function,
 _performComponentUpdate: Function,
 _processChildContext: Function,
 _processContext: Function,
 _processPendingState: Function,
 _processProps: Function,
 _renderValidatedComponent: Function,
 _renderValidatedComponentWithoutOwnerOrContext: Function,
 _replaceNodeWithMarkupByID: Function,
 _updateRenderedComponent: Function,
 attachRef: Function,
 construct: Function,
 constructor: Function,
 detachRef: Function,
 getName: Function,
 getPublicInstance: Function,
 mountComponent: Function,
 performUpdateIfNecessary: Function,
 receiveComponent: Function,
 unmountComponent: Function,
 updateComponent: Function,
 }
- Rendered Component
 component 组件实例 render 方法的返回结果 ReactDOM1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17ReactDOMComponent { 
 _currentElement: ReactElement
 _isOwnerNecessary: false
 _mountImage: null
 _mountIndex: 0
 _nodeWithLegacyProperties: null
 _previousStyle: null
 _previousStyleCopy: null
 _processedContextDev: Object
 _renderedChildren: null
 _rootNodeID: ".0"
 _tag: "div"
 _topLevelWrapper: null
 _unprocessedContextDev: Object
 _warnedAboutRefsInRender: false
 _wrapperState: null
 }
协调器算法(对比算法)
- 标记组件 dirty 是否需要更新
- 渲染所有实例等待更新
- 通过 对照变化 reconcile change 构建 新的变化 mutation list(new fiber tree)
- 更新 DOM 
对比算法的优化
https://www.zhihu.com/question/66851503
两颗 tree diff 遍历比较差异 O(n2) 再计算最小转化成本还要遍历一次,就是O(n3)。
react 通过假设只要遍历一遍 O(n):
- 不同类型的元素不需要比较,直接删除
- 元素不能垂直移动
- 列表通过 key 进行重用  
setState
只有 setState 和 ReactDOM.render 能触发更新
从 setState 调用到 DOM更新的完整内部生命周期

batchedUpdates
| 1 | function batchedUpdates<A, R>(fn: (a: A) => R, a: A): R { | 
requestWork
| 1 | function requestWork(root: FiberRoot, expirationTime: ExpirationTime) { | 
合成事件
- 事件跨浏览器跨平台兼容
- 事件池便于事件对象复用
- document 顶层事件委托 
react 17 改成 root 委托

event.persist() v16版本
https://deepscan.io/docs/rules/react-missing-event-persist
event pool
react v17 不再使用事件池,现代浏览器不需要重用不同事件之间的事件对象以提高旧浏览器的性能,并将它们之间的所有事件字段设置为 null。
https://stackoverflow.com/questions/36114196/what-is-event-pooling-in-react/36115815
Fiber
https://stackoverflow.com/questions/45341423/what-is-difference-between-react-vs-react-fiber
什么是 fiber
Fiber 是重新实现了 reconciler 更新机制的新架构。
一种虚拟堆栈帧,每个 fiber 都是一个任务一个帧。
可暂停/可优先/可记忆/可中止
本身不关心渲染,尽管 renderers 需要更改以支持并利用 fiber。
为什么用 fiber
- 动画、用户输入(动画流畅、UI 响应), 需要主线程 16ms 运行一次,当 script 执行任务时就会阻塞主线程直到 script 任务完成。
- 16版本之前的协调器算法一旦开始就停止不了,很大程度上 reconciler 依赖于递归调用, 所以很难使它停止再继续。1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23function reconcile(parentDom, instance, element) { 
 if (instance == null) {
 // Create instance
 // ..
 return newInstance;
 } else if (instance.element.type === element.type) {
 // Update instance
 //..
 instance.childInstances = reconcileChildren(instance, element);
 return instance;
 } else {
 // Replace instance ..
 }
 }
 function reconcileChildren(instance, element) {
 //...
 for (let i = 0; i < count; i++) {
 //...
 const newChildInstance = reconcile(dom, childInstance, childElement); // reconcile 递归
 }
 return newChildInstances;
 }
- 通过重写协调器算法,可以确定工作的优先级并加快整体帧速率。
 基于 fiber 的reconciler 更新 
fiber 结构关系

fiber 优先级
| 1 | ReactPriorityLevel { | 

fiber 会出现的问题
- componentWillUpdate 可能在 componentDidUpdate 之前被多次调用
- 没有哪个帧会保证何时会发生更新
- 可暂停/可优先/可记忆/可中止导致在 async mode 模式下,组件更新/渲染可能会被推迟,因此 react 可以提供一些高优先级的东西。这意味着每次 react 开始在你的组件上工作时都会调用 willUpdate,但它可能不会完成完整的更新,因此每次它开始在这个组件上工作时都会调用 willUpdate,但只会在这个过程完成后调用一次 didUpdate。 
 https://stackoverflow.com/questions/54533907/react-componentwillupdate-getting-called-twice
 从 v16.3.0 开始,componentWillUpdate 命周期方法已被弃用,鼓励在 componentDidUpdate 中处理任何副作用,这将在 render 方法之后触发