reconciliation 的设计
DOM仅是React支持的一个渲染环境,通过React Native它还可以支持原生IOS 和 Android页面的渲染。React 之所以能够支持如此多的渲染环境,主要是因为在设计上 reconciliation 和 rendering 是分离的阶段。reconciliation 负责计算树的哪些部分发生了变化;rendering 使用该信息来实际更新app。
reconciliation是一个过程,这个过程类似于Virtual Dom中所描述的。不同场景配置的api相似,但执行代码不同。react-reconciler支持React ART、React DOM、React Native。配置地址为:
virtual Dom
当渲染一个React 应用,会生成一棵描述应用结构的节点树,并保存在内存中。然后将此树刷新到呈现环境——例如,在浏览器应用程序的情况下,它被转换成一组DOM操作。也就是16前说的“Virtual Dom”。
虚拟DOM(VDOM)是一种编程概念(或称为“virtual”),是指虚拟的视图被保存在内存中,并通过诸如ReactDOM的库与“真实”DOM同步。这个过程被称为reconciliation。
在16版后,fibers 实现‘virtual Dom’的功能。‘virtual Dom’ 在不同的场景,指代的意思可能不一样(可Google)。16版后用fiber实现‘virtual’,使用 reconciliation 来代替这个过程。
什么是‘React Fiber’
在React 16中,Fiber是 reconciliation 引擎。fiber的主要目的是使 virtual DOM 能够进行增量渲染。
reconciliation api(接口)
支持的api为:
// packages\react-reconciler\src\forks\ReactFiberHostConfig.custom.jsexport const getPublicInstance = $$$hostConfig.getPublicInstance;export const getRootHostContext = $$$hostConfig.getRootHostContext;export const getChildHostContext = $$$hostConfig.getChildHostContext;export const prepareForCommit = $$$hostConfig.prepareForCommit;export const resetAfterCommit = $$$hostConfig.resetAfterCommit;export const createInstance = $$$hostConfig.createInstance;export const appendInitialChild = $$$hostConfig.appendInitialChild;export const finalizeInitialChildren = $$$hostConfig.finalizeInitialChildren;export const prepareUpdate = $$$hostConfig.prepareUpdate;export const shouldSetTextContent = $$$hostConfig.shouldSetTextContent;export const shouldDeprioritizeSubtree =$$$hostConfig.shouldDeprioritizeSubtree;export const createTextInstance = $$$hostConfig.createTextInstance;export const scheduleDeferredCallback = $$$hostConfig.scheduleDeferredCallback;export const cancelDeferredCallback = $$$hostConfig.cancelDeferredCallback;export const shouldYield = $$$hostConfig.shouldYield;export const scheduleTimeout = $$$hostConfig.setTimeout;export const cancelTimeout = $$$hostConfig.clearTimeout;export const noTimeout = $$$hostConfig.noTimeout;export const now = $$$hostConfig.now;export const isPrimaryRenderer = $$$hostConfig.isPrimaryRenderer;export const supportsMutation = $$$hostConfig.supportsMutation;export const supportsPersistence = $$$hostConfig.supportsPersistence;export const supportsHydration = $$$hostConfig.supportsHydration;// -------------------// Mutation// (optional)// -------------------export const appendChild = $$$hostConfig.appendChild;export const appendChildToContainer = $$$hostConfig.appendChildToContainer;export const commitTextUpdate = $$$hostConfig.commitTextUpdate;export const commitMount = $$$hostConfig.commitMount;export const commitUpdate = $$$hostConfig.commitUpdate;export const insertBefore = $$$hostConfig.insertBefore;export const insertInContainerBefore = $$$hostConfig.insertInContainerBefore;export const removeChild = $$$hostConfig.removeChild;export const removeChildFromContainer = $$$hostConfig.removeChildFromContainer;export const resetTextContent = $$$hostConfig.resetTextContent;export const hideInstance = $$$hostConfig.hideInstance;export const hideTextInstance = $$$hostConfig.hideTextInstance;export const unhideInstance = $$$hostConfig.unhideInstance;export const unhideTextInstance = $$$hostConfig.unhideTextInstance;// -------------------// Persistence// (optional)// -------------------export const cloneInstance = $$$hostConfig.cloneInstance;export const createContainerChildSet = $$$hostConfig.createContainerChildSet;export const appendChildToContainerChildSet = $$$hostConfig.appendChildToContainerChildSet;export const finalizeContainerChildren = $$$hostConfig.finalizeContainerChildren;export const replaceContainerChildren = $$$hostConfig.replaceContainerChildren;export const cloneHiddenInstance = $$$hostConfig.cloneHiddenInstance;export const cloneUnhiddenInstance = $$$hostConfig.cloneUnhiddenInstance;export const createHiddenTextInstance = $$$hostConfig.createHiddenTextInstance;// -------------------// Hydration// (optional)// -------------------export const canHydrateInstance = $$$hostConfig.canHydrateInstance;export const canHydrateTextInstance = $$$hostConfig.canHydrateTextInstance;export const getNextHydratableSibling = $$$hostConfig.getNextHydratableSibling;export const getFirstHydratableChild = $$$hostConfig.getFirstHydratableChild;export const hydrateInstance = $$$hostConfig.hydrateInstance;export const hydrateTextInstance = $$$hostConfig.hydrateTextInstance;export const didNotMatchHydratedContainerTextInstance =$$$hostConfig.didNotMatchHydratedContainerTextInstance;export const didNotMatchHydratedTextInstance =$$$hostConfig.didNotMatchHydratedTextInstance;export const didNotHydrateContainerInstance =$$$hostConfig.didNotHydrateContainerInstance;export const didNotHydrateInstance = $$$hostConfig.didNotHydrateInstance;export const didNotFindHydratableContainerInstance =$$$hostConfig.didNotFindHydratableContainerInstance;export const didNotFindHydratableContainerTextInstance =$$$hostConfig.didNotFindHydratableContainerTextInstance;export const didNotFindHydratableInstance = $$$hostConfig.didNotFindHydratableInstance;export const didNotFindHydratableTextInstance =$$$hostConfig.didNotFindHydratableTextInstance;
这些api并不都是必传,其中有Mutation、Persistence、Hydration中的api为可选的。
reconciliation 编译包
下载react源码,并执行
yarn run build
将生成各种不同的包,多的出乎你的想象,此处留作彩蛋,自己动手看。
react-reconciler 希望使用方提供配置,在编译react的时候,编译工具需要提供的场景进行相关的配置。在react 源码中,配置代码如下:
//... react\scripts\rollup\forks.js 289行代码for (let rendererInfo of inlinedHostConfigs) {if (rendererInfo.entryPoints.indexOf(entry) !== -1) {return `react-reconciler/src/forks/ReactFiberHostConfig.${rendererInfo.shortName}.js`;}}//..
根据 react-reconciler/src/forks 文件夹下的文件后缀,引入不同的配置。这些shortName就是react-concilier支持的场景。inlinedHostConfigs 指向一个配置文件,配置代码如下:
module.exports = [{shortName: 'dom',entryPoints: ['react-dom', 'react-dom/unstable-fizz.node'],isFlowTyped: true,isFizzSupported: true,},{shortName: 'dom-browser',entryPoints: ['react-dom/unstable-fizz.browser'],isFlowTyped: true,isFizzSupported: true,},{shortName: 'fire',entryPoints: ['react-dom/unstable-fire'],isFlowTyped: true,},{shortName: 'art',entryPoints: ['react-art'],isFlowTyped: false, // TODO: type it.isFizzSupported: false,},{shortName: 'native',entryPoints: ['react-native-renderer'],isFlowTyped: true,isFizzSupported: false,},{shortName: 'fabric',entryPoints: ['react-native-renderer/fabric'],isFlowTyped: true,isFizzSupported: false,},{shortName: 'test',entryPoints: ['react-test-renderer'],isFlowTyped: true,isFizzSupported: false,},{shortName: 'custom',entryPoints: ['react-reconciler','react-reconciler/persistent','react-stream',],isFlowTyped: true,isFizzSupported: true,},];
由上面的代码可以看出,16版后react-conciler 支持的场景有:dom、dom-browser、fire、art、native、fabric、test、custom。
