[Reactソースコードシリーズ]2-ノードの初期化

[Reactソースコードシリーズ]2-ノードの初期化

前のリンク:Reactソースコード学習シリーズ1-構成と操作

この記事は、主にポイントを必死に中断し、新しい名詞(関数)を覚えることについてです。理由(なぜこのように実行されるのか)ではなく、何(ここで何が実行されるのか)の質問を見てください。

  1. 走る()

    このコードはbabelによって実行され、関数は次のとおりです。

    function run(transformFn, script) {
          
          
      var scriptEl = document.createElement("script");
      scriptEl.text = transformCode(transformFn, script);
      headEl.appendChild(scriptEl);
    }
    

    なかでも、バベルの中transformFnからやってくるのですが、今はReactを学んでいるので、バベルにはあま​​り時間をかけていません。

    script内容は以下の通りです。

    const container = document.getElementById("container");
    
    // Create a root.
    const root = ReactDOM.createRoot(container);
    
    // Initial render
    root.render(<h1>Hello World</h1>);
    

    headElこれはbabel内の変数であり、この一般的な実行ロジックは、生成されしてレンダリングを完了することだと思います。scriptEl

  2. createRoot()

    追加する場合は、最初にオブジェクトを作成する必要があります。

    興味深いのは、実際にcreateRoot()はです。

    function createRoot$1(container, options) {
          
          
      {
          
          
        if (!Internals.usingClientEntryPoint) {
          
          
          error(
            'You are importing createRoot from "react-dom" which is not supported. ' +
              'You should instead import it from "react-dom/client".'
          );
        }
      }
    
      return createRoot(container, options);
    }
    

    それから再び本当createRoot()

    function createRoot(container, options) {
          
          
      if (!isValidContainer(container)) {
          
          
        throw new Error(
          "createRoot(...): Target container is not a DOM element."
        );
      }
    
      warnIfReactDOMContainerInDEV(container);
      var isStrictMode = false;
      var concurrentUpdatesByDefaultOverride = false;
      var identifierPrefix = "";
      var onRecoverableError = defaultOnRecoverableError;
      var transitionCallbacks = null;
    
      if (options !== null && options !== undefined) {
          
          
        {
          
          
          // 省略一堆 warning 和 error
        }
    
        if (options.unstable_strictMode === true) {
          
          
          isStrictMode = true;
        }
    
        if (options.identifierPrefix !== undefined) {
          
          
          identifierPrefix = options.identifierPrefix;
        }
    
        if (options.onRecoverableError !== undefined) {
          
          
          onRecoverableError = options.onRecoverableError;
        }
    
        if (options.transitionCallbacks !== undefined) {
          
          
          transitionCallbacks = options.transitionCallbacks;
        }
      }
    
      var root = createContainer(
        container,
        ConcurrentRoot,
        false,
        null,
        isStrictMode,
        concurrentUpdatesByDefaultOverride,
        identifierPrefix,
        onRecoverableError
      );
      markContainerAsRoot(root.current, container);
      var rootContainerElement =
        container.nodeType === COMMENT_NODE ? container.parentNode : container;
      listenToAllSupportedEvents(rootContainerElement);
      return new ReactDOMRoot(root);
    }
    

    いくつかの調査$のは公式には無意味ですが、慣例では$、関数の後に続く関数は1を返します。Observable [1]

  3. createContainer

    この関数の実行結果はテストポイントです。

    function createContainer(
      containerInfo,
      tag, // TODO: We can remove hydration-specific stuff from createContainer once
      // we delete legacy mode. The new root API uses createHydrationContainer.
      hydrate,
      hydrationCallbacks,
      isStrictMode,
      concurrentUpdatesByDefaultOverride,
      identifierPrefix,
      onRecoverableError,
      transitionCallbacks
    ) {
          
          
      return createFiberRoot(
        containerInfo,
        tag,
        hydrate,
        hydrationCallbacks,
        isStrictMode,
        concurrentUpdatesByDefaultOverride,
        identifierPrefix,
        onRecoverableError
      );
    }
    

    はい、伝説のファイバーはここから始まりました。

  4. createFiberRoot

    function createFiberRoot(
      containerInfo,
      tag,
      hydrate,
      hydrationCallbacks,
      isStrictMode,
      concurrentUpdatesByDefaultOverride, // TODO: We have several of these arguments that are conceptually part of the
      // host config, but because they are passed in at runtime, we have to thread
      // them through the root constructor. Perhaps we should put them all into a
      // single type, like a DynamicHostConfig that is defined by the renderer.
      identifierPrefix,
      onRecoverableError,
      transitionCallbacks
    ) {
          
          
      var root = new FiberRootNode(
        containerInfo,
        tag,
        hydrate,
        identifierPrefix,
        onRecoverableError
      );
      // stateNode is any.
    
      var uninitializedFiber = createHostRootFiber(tag, isStrictMode);
      root.current = uninitializedFiber;
      uninitializedFiber.stateNode = root;
    
      {
          
          
        var initialCache = createCache();
        retainCache(initialCache); // The pooledCache is a fresh cache instance that is used temporarily
        // for newly mounted boundaries during a render. In general, the
        // pooledCache is always cleared from the root at the end of a render:
        // it is either released when render commits, or moved to an Offscreen
        // component if rendering suspends. Because the lifetime of the pooled
        // cache is distinct from the main memoizedState.cache, it must be
        // retained separately.
    
        root.pooledCache = initialCache;
        retainCache(initialCache);
        var initialState = {
          
          
          element: null,
          cache: initialCache,
          transitions: null,
        };
        uninitializedFiber.memoizedState = initialState;
      }
    
      initializeUpdateQueue(uninitializedFiber);
      return root;
    }
    
  5. createHostRootFiber

    ここでもキーワード:並行。

    function createHostRootFiber(
      tag,
      isStrictMode,
      concurrentUpdatesByDefaultOverride
    ) {
          
          
      var mode;
    
      if (tag === ConcurrentRoot) {
          
          
        mode = ConcurrentMode;
    
        if (isStrictMode === true) {
          
          
          mode |= StrictLegacyMode;
    
          {
          
          
            mode |= StrictEffectsMode;
          }
        }
      } else {
          
          
        mode = NoMode;
      }
    
      if (isDevToolsPresent) {
          
          
        // Always collect profile timings when DevTools are present.
        // This enables DevTools to start capturing timing at any point–
        // Without some nodes in the tree having empty base times.
        mode |= ProfileMode;
      }
    
      return createFiber(HostRoot, null, null, mode);
    }
    

    ご覧のとおりcreateHostRootFiber通常のFiberNodeとの最大の違いはおそらく初期化です。mode

  6. ファイバーノード

    ファイバーノードの初期化については何も言うことはありませんが、ソースコードには興味深いコメントがあります。

    注:以下は、v8パフォーマンスの低下を回避するために行われます。
    以下のフィールドをsmisに初期化し、後でそれらを
    double値で更新すると、ファイバーは別々の形状になります。
    この動作/バグはObject.preventExtension()と関係があります。
    幸い、これはDEVビルドにのみ影響します。
    残念ながら、一部のアプリケーションではReactが使用できないほど遅くなります。
    これを回避するには、以下のフィールドをdoubleで初期化します。

    詳細については、こちらをご覧ください。

    https://github.com/facebook/react/issues/14365

    https://bugs.chromium.org/p/v8/issues/detail?id=8538

    この問題とこの発生したバグについては後で確認する予定です。

  7. markContainerAsRoot

    このコードは単純です:

    function markContainerAsRoot(hostRoot, node) {
          
          
      node[internalContainerInstanceKey] = hostRoot;
    }
    

    internalContainerInstanceKey名前は、現在のインスタンスを管理するための一意のキーである必要があります。後で、このキーがどのように生成されるか、および各更新との関係を確認することもできます。

  8. listenToAllSupportedEvents

    ここでは、イベントハンドラーを個別に分解します。Reactが内部でイベント処理の処理も行っていることがわかります。

  9. 新しいReactDOMRoot(root)

    これは実際には内部ノードをバインドしています。

    function ReactDOMRoot(internalRoot) {
          
          
      this._internalRoot = internalRoot;
    }
    

    その後、このノードは最も早い追加セグメントに戻されます。

    この時点で、空白のノード(Node)が生成されました。次のステップは、新しい要素をcreateElement作成し、renderそれを介してレンダリングすることです。

フローチャット

プロセスツリーを更新します。

1
2
3
createRoot$1(HTMLNode: container): ReactDOMRoot
createRoot(HTMLNode: container): ReactDOMRoot
createContainer(...args): FiberRoot
markContainerAsRoot(...args): void
listenToAllSupportedEvents(FiberRoot: root): void
createFiberRoot(...args): FiberRoot
createHostRootFiber(...args): Fiber
createFiber(...args): FiberNode
run
render
appendChild
retainCache
initializeUpdateQueue

参照

1関数名の末尾の$記号は何を示していますか?

おすすめ

転載: blog.csdn.net/weixin_42938619/article/details/124032368