Реагируйте на компоненты с предварительной загрузкой с помощью Lazy + Suspense

В настоящее время я использую React 16 с Suspense и Lazy для разделения кода моей кодовой базы. Хотя хотелось бы предзагрузить компоненты.

В моем примере ниже у меня есть два маршрута. Есть ли способ предварительно загрузить Demo сразу после монтирования Prime? Я попытался создать еще один динамический импорт в componentDidMount страницы Prime, но React.lazy, похоже, не может получить тот же файл, что и динамический импорт ниже.

import React, { lazy, Suspense } from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import GlobalStyle from 'styles';

import Loading from 'common/Loading';
const Prime = lazy(() => import(/* webpackChunkName: "Prime" */'modules/Prime'));
const Demo = lazy(() => import(/* webpackChunkName: "Demo" */'modules/Demo'));

const App = () => (
  <main>
    <GlobalStyle />
    <Suspense fallback = {<Loading>Loading...</Loading>}>
      <Switch>
        <Route path = "/" component = {Prime} exact />
        <Route path = "/demo" component = {Demo} />
      </Switch>
    </Suspense>
  </main>
);

export default withRouter(App);

Итак, я пробовал разные подходы, например, с webpackChunkName и без него, а также различные способы импорта другого компонента в componentDidMount, как показано ниже. Первые два подхода к импорту файла в componentDidMount привели к ошибке Webpack, показанной внизу изображения ниже. Только третий продолжил работу, но сделал файл 2.[hash].js в образе, загружаемый только после посещения страницы, а не на componentDidMount

Реагируйте на компоненты с предварительной загрузкой с помощью Lazy + Suspense

Что мне здесь не хватает?

Код modules/Demo.jsx:

import React from 'react';

import LogoIcon from 'vectors/logo.svg';
import PageLink from 'common/PageLink';
import Anchor from 'common/Anchor';
import CenteredSection from 'common/CenteredSection';

const Demo = () => (
  <CenteredSection variant = "green">
    <LogoIcon />
    <PageLink to = "/" variant = "green">Go to home page</PageLink>
  </CenteredSection>
);

export default Demo;

Использование lazy в componentDidMount of Prime не принесет вам никакой пользы для случая предварительной загрузки, поскольку оно вызывает загрузку компонента при его рендеринге. Подходы 2 и 3 на первый взгляд кажутся хорошими, но ошибка, которую вы получаете для 1 и 2, заставляет меня хотеть увидеть код для modules/Demo, поскольку кажется, что что-то вызывает циклическую зависимость.

Ryan Cogswell 11.11.2018 22:05

@RyanC благодарит за ответ. Я добавил код демонстрационной страницы. Вы также можете просмотреть кодовую базу здесь: github.com/JBostelaar/react-prime/tree/progressive-web-app/s‌ rc Я тоже думал, что первый подход не сработает, но все же я хотел показать, что я пробовал. 2 выдает ошибку, 3 не загружает страницу предварительно.

ronnyrr 11.11.2018 22:45

Структура кода немного отличается от того, что я ожидал. Я ожидал увидеть modules/Demo.jsx и modules/Prime.jsx. Я не говорю, что то, что у вас есть, «неправильно», но наличие Demo/index.jsx вместо этого просто отклоняется от подходов, которые я использовал, и я могу дать более уверенное направление.

Ryan Cogswell 11.11.2018 22:55

Спасибо за ваш вклад, но я почти уверен, что проблема не в структуре моих папок или именовании.

ronnyrr 11.11.2018 23:00

Хорошее использование webpackChunkName. Не знал, что можно так называть свои куски, спасибо;)

webmaster 08.03.2019 16:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
12
5
5 604
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Не уверен, насколько это поможет, но вот песочница кода, который работает (демонстрация загружается с помощью componentDidMount). Это значительно упрощенная версия вашего кода, использующая приложение create-response-app для config. Возможно, вы можете взять это за отправную точку и постепенно преобразовать ее ближе к своему приложению, чтобы увидеть, из-за чего динамический импорт больше не работает должным образом.

Ответ принят как подходящий

Это невероятно легко сделать, я думаю, что существует неправильное понимание того, что делают lazy () и Suspense под капотом.

Единственное ожидание, которое имеет React.lazy (), - это то, что он принимает функцию, которая возвращает обещание, которое разрешается с помощью компонента по умолчанию.

React.lazy(() => Promise<{default: MyComponent}>)

Поэтому, если вы хотите выполнить предварительную загрузку, все, что вам нужно сделать, это выполнить обещание заранее.

// So change this, which will NOT preload
import React from 'react';
const MyLazyComp = React.lazy(() => import('./path/to/component'));

/*********************************************/

// To this, which WILL preload
import React from 'react';

// kicks off immediately when the current file is imported
const componentPromise = import('./path/to/component');

// by the time this gets rendered, your component is probably already loaded
// Suspense still works exactly the same with this.
const MyLazyComp = React.lazy(() => componentPromise);

Тот факт, что это известная сигнатура, делает ее полезной во многих других ситуациях. Например, у меня есть несколько компонентов, которые полагаются на динамическую загрузку api карт Google, я смог создать функцию, которая загружает api карт Google, а затем импортирует компонент. Я не буду подробно останавливаться на деталях этого примера, поскольку он является касательным, но дело в том, что я сделал себе функцию, которая выполняет кучу асинхронных операций, а затем возвращает Promise с объектом {default: Component}.

import React from 'react';
const MyLazyComp = React.lazy(() => importMapsComponent('./path/to/comp'));

Другие вопросы по теме