反应延迟加载的组件失去它的状态(被卸载)

Ash*_*sha 5 lazy-loading reactjs react-router react-hooks

我有以下组件可以在需要时加载我的组件(在路线更改时)。

function DynamicLoader(props) {
  const LazyComponent = React.lazy(() => import(`${props.component}`));
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  );
}
Run Code Online (Sandbox Code Playgroud)

我的路由(使用 React-Router)如下所示:

            <Switch>
            {routes.map((prop, key) => {
              return (
                <Route
                  exact
                  path={prop.path}
                  render={() => (
                    <DynamicLoader component={prop.component} />
                  )}
                  key={key}
                />
              );
            })}
          </Switch>
Run Code Online (Sandbox Code Playgroud)

就为每个路由安装组件而言,这工作正常,但是看起来随着父组件的每次更改,React 正在卸载并重新安装延迟加载的组件(而不是重新渲染)。这会导致所有内部状态重置,这当然是不希望的。任何人都可以推荐任何解决方案吗?这是一个显示此问题的代码和框

Ori*_*ori 11

每当渲染父级时,都会DynamicLoader重新创建LazyComponent. React 看到一个新组件(不是同一个对象),卸载前一个组件,然后安装到新组件。

要解决此问题,请使用React.useMemo()insideDynamicLoader来记忆当前的LazyComponent,并且仅在props.component实际更改时重新创建它:

const DynamicLoader = ({ component, parentUpdate }) => {
  const LazyComponent = useMemo(() => React.lazy(() => import(component)), [
    component
  ]);

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent parentUpdate={parentUpdate} />
    </Suspense>
  );
};
Run Code Online (Sandbox Code Playgroud)

沙箱- 为了展示 memoized LazyComponent,我将外部传递updateHomeA组件。

由于useMemo()无法保证缓存(React 可能会不时释放内存),因此您可以使用以下方法编写一个简单的延迟缓存Map

const componentsMap = new Map();

const useCachedLazy = (component) => {
  useEffect(
    () => () => {
      componentsMap.delete(component);
    },
    [component]
  );

  if (!componentsMap.has(component)) {
    componentsMap.set(
      component,
      React.lazy(() => import(component))
    );
  }

  return componentsMap.get(component);
};

const DynamicLoader = ({ component, parentUpdate }) => {
  const LazyComponent = useCachedLazy(component);

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent parentUpdate={parentUpdate} />
    </Suspense>
  );
};
Run Code Online (Sandbox Code Playgroud)

沙盒