1. import React from 'react';
    
  2. import {useContext, useMemo, useRef, useState, useLayoutEffect} from 'react';
    
  3. import {__RouterContext} from 'react-router';
    
  4. import {ReactReduxContext} from 'react-redux';
    
  5. 
    
  6. import ThemeContext from './shared/ThemeContext';
    
  7. 
    
  8. let rendererModule = {
    
  9.   status: 'pending',
    
  10.   promise: null,
    
  11.   result: null,
    
  12. };
    
  13. 
    
  14. export default function lazyLegacyRoot(getLegacyComponent) {
    
  15.   let componentModule = {
    
  16.     status: 'pending',
    
  17.     promise: null,
    
  18.     result: null,
    
  19.   };
    
  20. 
    
  21.   return function Wrapper(props) {
    
  22.     const createLegacyRoot = readModule(
    
  23.       rendererModule,
    
  24.       () => import('../legacy/createLegacyRoot')
    
  25.     ).default;
    
  26.     const Component = readModule(componentModule, getLegacyComponent).default;
    
  27.     const containerRef = useRef(null);
    
  28.     const rootRef = useRef(null);
    
  29. 
    
  30.     // Populate every contexts we want the legacy subtree to see.
    
  31.     // Then in src/legacy/createLegacyRoot we will apply them.
    
  32.     const theme = useContext(ThemeContext);
    
  33.     const router = useContext(__RouterContext);
    
  34.     const reactRedux = useContext(ReactReduxContext);
    
  35.     const context = useMemo(
    
  36.       () => ({
    
  37.         theme,
    
  38.         router,
    
  39.         reactRedux,
    
  40.       }),
    
  41.       [theme, router, reactRedux]
    
  42.     );
    
  43. 
    
  44.     // Create/unmount.
    
  45.     useLayoutEffect(() => {
    
  46.       if (!rootRef.current) {
    
  47.         rootRef.current = createLegacyRoot(containerRef.current);
    
  48.       }
    
  49.       const root = rootRef.current;
    
  50.       return () => {
    
  51.         root.unmount();
    
  52.       };
    
  53.     }, [createLegacyRoot]);
    
  54. 
    
  55.     // Mount/update.
    
  56.     useLayoutEffect(() => {
    
  57.       if (rootRef.current) {
    
  58.         rootRef.current.render(Component, props, context);
    
  59.       }
    
  60.     }, [Component, props, context]);
    
  61. 
    
  62.     return <div style={{display: 'contents'}} ref={containerRef} />;
    
  63.   };
    
  64. }
    
  65. 
    
  66. // This is similar to React.lazy, but implemented manually.
    
  67. // We use this to Suspend rendering of this component until
    
  68. // we fetch the component and the legacy React to render it.
    
  69. function readModule(record, createPromise) {
    
  70.   if (record.status === 'fulfilled') {
    
  71.     return record.result;
    
  72.   }
    
  73.   if (record.status === 'rejected') {
    
  74.     throw record.result;
    
  75.   }
    
  76.   if (!record.promise) {
    
  77.     record.promise = createPromise().then(
    
  78.       value => {
    
  79.         if (record.status === 'pending') {
    
  80.           record.status = 'fulfilled';
    
  81.           record.promise = null;
    
  82.           record.result = value;
    
  83.         }
    
  84.       },
    
  85.       error => {
    
  86.         if (record.status === 'pending') {
    
  87.           record.status = 'rejected';
    
  88.           record.promise = null;
    
  89.           record.result = error;
    
  90.         }
    
  91.       }
    
  92.     );
    
  93.   }
    
  94.   throw record.promise;
    
  95. }