React Structure

React 源代码基础结构理解:
React Hooks 学习杂记 - 图1

  • React Core: all top-level APIs;React core only includes the APIs necessary to define components
  • React Render: ReactDOMRender / ReactNativeRender / RaxRender / WeexRender …
  • React Reconcilers: share a lot of logic among different renders, especially the declarative rendering algorithms, reconciliation algorithm.
    • Stack Reconciler (React 15 based)
    • Fiber Reconciler (React 16 based)

:::info 分层架构,IoC 的实践;经济体的 LowcodeEngine 也借鉴了不少类似的分层模式; :::

Hooks

React Hooks 学习杂记 - 图2

  1. export function useEffect(
  2. create: () => (() => void) | void,
  3. deps: Array<mixed> | void | null,
  4. ): void {
  5. const dispatcher = resolveDispatcher();
  6. return dispatcher.useEffect(create, deps);
  7. }
  • Fiber Tree
  • Fiber:renderWithHooks 函数的实现背景
  • Dispatcher & Resolver ReactFiberHooks.new.js
    • ReactCurrentDispatcher.current 👈 为了兼容渲染层 RenderDriver 而实现的 .current 指向 ReactDOM or ReactNative or Remax Driver
  • Mount Hook on Fiber
  1. function mountWorkInProgressHook(): Hook {
  2. const hook: Hook = {
  3. memoizedState: null,
  4. baseState: null,
  5. baseQueue: null,
  6. queue: null,
  7. next: null,
  8. };
  9. if (workInProgressHook === null) {
  10. // This is the first hook in the list
  11. currentlyRenderingFiber.memoizedState = workInProgressHook = hook;
  12. } else {
  13. // Append to the end of the list
  14. workInProgressHook = workInProgressHook.next = hook;
  15. }
  16. return workInProgressHook;
  17. }
  • useState() :
    • 初始化:数据、调用队列和 Reducer
    • 更新:dispatchAction => Fiber 节点上的 queue 对象,链式处理 state
  • useEffect():
    • 初始化:Fiber 节点的 updateQueue,并使用 .next 属性做关联实现调用链

一些小技巧

  • React 源代码组织: pacakges/share 公共类型、API、方法的目录;
  • __DEV__ 区分编译时和运行时;
  • ReactFuatureFlags & |= Operator 的奇妙用法;用 bitwise 运算去巧妙解决 flags 的问题;

    1. currentlyRenderingFiber.effectTag |= fiberEffectTag;
  • invariant() function and console.error function;Runtime v.s. Compile Time; ```javascript /**

    • Use invariant() to assert state which your program assumes to be true. *
    • Provide sprintf-style format (only %s is supported) and arguments
    • to provide information about what broke and what you were
    • expecting. *
    • The invariant message will be stripped in production, but the invariant
    • will remain to ensure logic does not differ in production. */

export default function invariant(condition, format, a, b, c, d, e, f) { throw new Error( ‘Internal React error: invariant() is meant to be replaced at compile ‘ + ‘time. There is no runtime version.’, ); }

  1. - 经典的: `__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED` 猜测一下为啥要透露这些变量呢?
  2. ```javascript
  3. React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
  4. const ReactSharedInternals = {
  5. ReactCurrentDispatcher,
  6. ReactCurrentBatchConfig,
  7. ReactCurrentOwner,
  8. IsSomeRendererActing,
  9. // Used by renderers to avoid bundling object-assign twice in UMD bundles:
  10. assign,
  11. };

感受

  • React 级别的项目,洁癖也没有「那么好」😄
  • Comment / DevInfo 至关重要
  • flow 🗑
  • comment system 各种自我怀疑

image.png

使用 Hooks 注意

  • 防止在条件、循环、return 语句中使用 Hooks
  • 没有 re-render 的需求的渲染函数,尽量少用 useState,相反,使用 useRef 减少重新渲染次数
  • useEffect 的依赖和销毁回调函数需要引起重视
  • 涉及多次 setState 的 Hook 函数调用的时候,优先选择函数而非具体值

参考