目录
扩展学习资料
React Reconciliation
Stack Reconciler【15版本、栈协调】
Stack Reconciler-事务性
事务性带来的弊端:
扩展学习资料
名称 | 链接 | 备注 |
官方文档 | Reconciliation – React | 英文 |
stack reconciler | Implementation Notes – React | 英文 |
react fiber | What is React Fiber ? | Giamir Buoncristiani | 英文 |
React Fiber 初探 | React Fiber 初探 - 掘金 | |
React Fiber 架构 | React Fiber架构 - 知乎 |
react协调:Virtual Dom转化成真实UI的过程
React Reconciliation
主要协调方式:
- Stack Reconciler【15版本、栈协调】
- Fiber Reconciler【16版本、Fiber协调】
Stack Reconciler【15版本、栈协调】
React的初次渲染
- 这是一个很简单的demo,定义了组件App,输出一段文本。
- 里面依赖渲染state的变量text,在这里我们先用文本替代。
class App extends React.Component {render() { const {text} = this.state;return <div className='app'>react 15.6.2 first render</div>;}
}
代码图示
.jsx文件通过babel转义调用react的createElement
- lib/ReactMount.js中申明了render方法,其实现如下:
// 即将渲染的组件,挂载节点, 回调函数
render: function (nextElement, container, callback) {return ReactMount._renderSubtreeIntoContainer(null, nextElement, container, callback)
}
- _renderSubtreeIntoContainer 方法是渲染子树到container节点里面的,container是我们在html定义的根节点。
var component = ReactMount._renderNewRootComponent(nextWrappedElement, container, shouldReuseMarkup, nextContext)
._renderedComponent.getPublicInstance();
- lib/ReactMount.js基本上就是React第一次渲染的完整过程体现,里面会引用很多辅助模块。renderNewRootComponent中关键代码:
// 初始化React组件的方法
var componentInstance = instantiateReactComponent(nextElement, false);
- 生成根组件实例之后就开始渲染,该组件实例是挂载根组件的实例,instantiateReactComponent方法就是接受一个React节点,返回一个挂载的实例。
instance = new ReactCompositeComponentWrapper(element);
// react所有组件包装器,继承了react所有组件
- ReactCompositeComponent类就是React中组件的组合,包含了React的组件类别,以及React组件的声明周期函数挂载。
- batchedMountComponentIntoNode方法执行批量挂载。
- mountComponentIntoNode方法执行组件挂载。
var CompositeTypes = { // 对react组件进行收敛,通过传进的类型,进行组件类型判断ImpureClass: 0,PureClass: 1,StatelessFunctional: 2
};
// 组件渲染到dom的重要方法
var markup = ReactReconciler.mountComponent(wrapperInstance, transaction, null,
ReactDOMContainerInfo(wrapperInstance, container), context, 0 /* parentDrbugID */);
// 批量挂载
// batchedMountComponentIntoNode(markup)
// 组件挂载到html节点
// mountComponentIntoNode(markup)
- mountComponent方法最后会调用_mountImageIntoNode方法,作用是把前面产生的‘markup’渲染到HTML节点中去。
- _mountImageIntoNode中由于是第一次渲染节点,所以会执行insertTreeBefore方法。insertTreeBefore就是最底层的DOM API执行插入HTML节点。
ReactMount._mountImageIntoNode(markup, container, wrapperInstance, shouldReuseMarkup, transaction);
DOMLazyTree.insertTreeBefore(container, markup, null);
// 最底层的DOM API执行插入/更新HTML节点
- setState
1. enqueueSetState setState 常规的调用执行函数
2. enqueueCallback setState 带回调函数的执行函数
- componentWillReceiveProps
通常props发生改变,也会触发再次渲染,不过更多的处理逻辑是在
componentWillReceiveProps里面执行一些逻辑判断,最后执行this.setState方法
enqueueUpdate
- enqueueUpdate判断当前是否在更新中。如未更新,则dirtyComponents会将当前component加入到数组中。
- 如isBatchingUpdates为true,页面不会立刻触发批量更新。
- 侧面反映setState调用后不会立即执行更新,所以在setState之后立即取值state,还会是之前的值。
if(!batchingStrategy.isBatchingUpdates) {// 通常会是true,所以setState是异步batchingStrategy.batchedUpdates(// 更新策略-批量更新enqueueUpdate,// 更新队列component, // 更新组件 );return;
}
// 待更新,组件数组
dirtyComponents.push(component);
if (component._updateBatchNumber == null) {// 待更新数+1component._updateBatchNumber = updateBatchNumber + 1;
}
Stack Reconciler-事务性
事务性带来的弊端:
由事务性导致它的更新是一气呵成的,在组件比较复杂,耗时比较长的时候,与此同时,如果有用户输入、点击。【浏览器没有将这些事件定义为高优先级,一视同仁】就会比较卡顿,因为大部分运算还是在处理更新渲染。【渲染过程不可阻断,一旦页面更新过于复杂,耗时过长,页面操作就会卡顿】
setState是大部分情况是异步的【onClick,onChange,组件生命周期调用】
setState不处于事务性更新过程时,是同步的【新的更新周期时是立刻执行的】