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为:

  1. // packages\react-reconciler\src\forks\ReactFiberHostConfig.custom.js
  2. export const getPublicInstance = $$$hostConfig.getPublicInstance;
  3. export const getRootHostContext = $$$hostConfig.getRootHostContext;
  4. export const getChildHostContext = $$$hostConfig.getChildHostContext;
  5. export const prepareForCommit = $$$hostConfig.prepareForCommit;
  6. export const resetAfterCommit = $$$hostConfig.resetAfterCommit;
  7. export const createInstance = $$$hostConfig.createInstance;
  8. export const appendInitialChild = $$$hostConfig.appendInitialChild;
  9. export const finalizeInitialChildren = $$$hostConfig.finalizeInitialChildren;
  10. export const prepareUpdate = $$$hostConfig.prepareUpdate;
  11. export const shouldSetTextContent = $$$hostConfig.shouldSetTextContent;
  12. export const shouldDeprioritizeSubtree =
  13. $$$hostConfig.shouldDeprioritizeSubtree;
  14. export const createTextInstance = $$$hostConfig.createTextInstance;
  15. export const scheduleDeferredCallback = $$$hostConfig.scheduleDeferredCallback;
  16. export const cancelDeferredCallback = $$$hostConfig.cancelDeferredCallback;
  17. export const shouldYield = $$$hostConfig.shouldYield;
  18. export const scheduleTimeout = $$$hostConfig.setTimeout;
  19. export const cancelTimeout = $$$hostConfig.clearTimeout;
  20. export const noTimeout = $$$hostConfig.noTimeout;
  21. export const now = $$$hostConfig.now;
  22. export const isPrimaryRenderer = $$$hostConfig.isPrimaryRenderer;
  23. export const supportsMutation = $$$hostConfig.supportsMutation;
  24. export const supportsPersistence = $$$hostConfig.supportsPersistence;
  25. export const supportsHydration = $$$hostConfig.supportsHydration;
  26. // -------------------
  27. // Mutation
  28. // (optional)
  29. // -------------------
  30. export const appendChild = $$$hostConfig.appendChild;
  31. export const appendChildToContainer = $$$hostConfig.appendChildToContainer;
  32. export const commitTextUpdate = $$$hostConfig.commitTextUpdate;
  33. export const commitMount = $$$hostConfig.commitMount;
  34. export const commitUpdate = $$$hostConfig.commitUpdate;
  35. export const insertBefore = $$$hostConfig.insertBefore;
  36. export const insertInContainerBefore = $$$hostConfig.insertInContainerBefore;
  37. export const removeChild = $$$hostConfig.removeChild;
  38. export const removeChildFromContainer = $$$hostConfig.removeChildFromContainer;
  39. export const resetTextContent = $$$hostConfig.resetTextContent;
  40. export const hideInstance = $$$hostConfig.hideInstance;
  41. export const hideTextInstance = $$$hostConfig.hideTextInstance;
  42. export const unhideInstance = $$$hostConfig.unhideInstance;
  43. export const unhideTextInstance = $$$hostConfig.unhideTextInstance;
  44. // -------------------
  45. // Persistence
  46. // (optional)
  47. // -------------------
  48. export const cloneInstance = $$$hostConfig.cloneInstance;
  49. export const createContainerChildSet = $$$hostConfig.createContainerChildSet;
  50. export const appendChildToContainerChildSet = $$$hostConfig.appendChildToContainerChildSet;
  51. export const finalizeContainerChildren = $$$hostConfig.finalizeContainerChildren;
  52. export const replaceContainerChildren = $$$hostConfig.replaceContainerChildren;
  53. export const cloneHiddenInstance = $$$hostConfig.cloneHiddenInstance;
  54. export const cloneUnhiddenInstance = $$$hostConfig.cloneUnhiddenInstance;
  55. export const createHiddenTextInstance = $$$hostConfig.createHiddenTextInstance;
  56. // -------------------
  57. // Hydration
  58. // (optional)
  59. // -------------------
  60. export const canHydrateInstance = $$$hostConfig.canHydrateInstance;
  61. export const canHydrateTextInstance = $$$hostConfig.canHydrateTextInstance;
  62. export const getNextHydratableSibling = $$$hostConfig.getNextHydratableSibling;
  63. export const getFirstHydratableChild = $$$hostConfig.getFirstHydratableChild;
  64. export const hydrateInstance = $$$hostConfig.hydrateInstance;
  65. export const hydrateTextInstance = $$$hostConfig.hydrateTextInstance;
  66. export const didNotMatchHydratedContainerTextInstance =
  67. $$$hostConfig.didNotMatchHydratedContainerTextInstance;
  68. export const didNotMatchHydratedTextInstance =
  69. $$$hostConfig.didNotMatchHydratedTextInstance;
  70. export const didNotHydrateContainerInstance =
  71. $$$hostConfig.didNotHydrateContainerInstance;
  72. export const didNotHydrateInstance = $$$hostConfig.didNotHydrateInstance;
  73. export const didNotFindHydratableContainerInstance =
  74. $$$hostConfig.didNotFindHydratableContainerInstance;
  75. export const didNotFindHydratableContainerTextInstance =
  76. $$$hostConfig.didNotFindHydratableContainerTextInstance;
  77. export const didNotFindHydratableInstance = $$$hostConfig.didNotFindHydratableInstance;
  78. export const didNotFindHydratableTextInstance =$$$hostConfig.didNotFindHydratableTextInstance;

这些api并不都是必传,其中有Mutation、Persistence、Hydration中的api为可选的。

reconciliation 编译包

下载react源码,并执行

yarn run build

将生成各种不同的包,多的出乎你的想象,此处留作彩蛋,自己动手看。

react-reconciler 希望使用方提供配置,在编译react的时候,编译工具需要提供的场景进行相关的配置。在react 源码中,配置代码如下:

  1. //... react\scripts\rollup\forks.js 289行代码
  2. for (let rendererInfo of inlinedHostConfigs) {
  3. if (rendererInfo.entryPoints.indexOf(entry) !== -1) {
  4. return `react-reconciler/src/forks/ReactFiberHostConfig.${
  5. rendererInfo.shortName
  6. }.js`;
  7. }
  8. }
  9. //..

根据 react-reconciler/src/forks 文件夹下的文件后缀,引入不同的配置。这些shortName就是react-concilier支持的场景。inlinedHostConfigs 指向一个配置文件,配置代码如下:

  1. module.exports = [
  2. {
  3. shortName: 'dom',
  4. entryPoints: ['react-dom', 'react-dom/unstable-fizz.node'],
  5. isFlowTyped: true,
  6. isFizzSupported: true,
  7. },
  8. {
  9. shortName: 'dom-browser',
  10. entryPoints: ['react-dom/unstable-fizz.browser'],
  11. isFlowTyped: true,
  12. isFizzSupported: true,
  13. },
  14. {
  15. shortName: 'fire',
  16. entryPoints: ['react-dom/unstable-fire'],
  17. isFlowTyped: true,
  18. },
  19. {
  20. shortName: 'art',
  21. entryPoints: ['react-art'],
  22. isFlowTyped: false, // TODO: type it.
  23. isFizzSupported: false,
  24. },
  25. {
  26. shortName: 'native',
  27. entryPoints: ['react-native-renderer'],
  28. isFlowTyped: true,
  29. isFizzSupported: false,
  30. },
  31. {
  32. shortName: 'fabric',
  33. entryPoints: ['react-native-renderer/fabric'],
  34. isFlowTyped: true,
  35. isFizzSupported: false,
  36. },
  37. {
  38. shortName: 'test',
  39. entryPoints: ['react-test-renderer'],
  40. isFlowTyped: true,
  41. isFizzSupported: false,
  42. },
  43. {
  44. shortName: 'custom',
  45. entryPoints: [
  46. 'react-reconciler',
  47. 'react-reconciler/persistent',
  48. 'react-stream',
  49. ],
  50. isFlowTyped: true,
  51. isFizzSupported: true,
  52. },
  53. ];

由上面的代码可以看出,16版后react-conciler 支持的场景有:dom、dom-browser、fire、art、native、fabric、test、custom。