Реагировать на загруженный компонент Lazy, теряя свое состояние (отключается) - PullRequest
2 голосов
/ 04 июля 2019

У меня есть следующий компонент, который загружает мои компоненты при необходимости (при изменении маршрута).

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

А мои маршруты (с использованием React-Router) выглядят так:

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

Это работает нормально, когда монтируется компонент для каждого маршрута, однако при каждом изменении родительского компонента React отключает и перемонтирует загруженный компонент с отложенной загрузкой (вместо повторного рендеринга).И это вызывает сброс всех внутренних состояний, что, конечно, нежелательно.Кто-нибудь может порекомендовать какое-либо решение, пожалуйста?Вот codesandbox , показывающий эту проблему.

1 Ответ

1 голос
/ 05 июля 2019

При каждом отображении родителя DynamicLoader воссоздает LazyComponent. React видит новый компонент (не тот же объект), отключает предыдущий и монтирует новый.

Чтобы решить эту проблему, используйте React.useMemo() внутри DynamicLoader для запоминания текущего 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>
  );
};

Песочница - чтобы продемонстрировать запомненный LazyComponent, я передаю внешний update компоненту HomeA.

Поскольку useMemo() кэширование не гарантировано (реакция может время от времени освобождать память), вы можете написать простое ленивое кэширование, используя Map:

const componentsMap = new Map();

const getCachedLazy = component => {
  if (componentsMap.has(component)) return componentsMap.get(component);

  const Component = React.lazy(() => import(component));

  componentsMap.set(component, Component);

  return Component;
};

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

  return (
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent parentUpdate={parentUpdate} />
    </Suspense>
  );
};

Песочница

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...