Современные JavaScript приложения могут быть довольно большими с точки зрения размера bundle
пакета. Вам бы не хотелось, чтобы ваши пользователи загружали JavaScript пакет объемом в 1 МБ (ваш код и библиотеки, которые вы используете) только для загрузки первой страницы, верно? Но это то, что происходит по умолчанию, в современном веб-приложении, собраном с помощью Webpack.
Этот пакет будет содержать код, который может никогда и не запуститься, в случае если пользователь останится только на главной странице.
Разделение кода - это практика загрузки только того JavaScript-кода, который вам нужен в определенный момент времени и тогда, когда вам это нужно.
Это улучшает:
- производительность вашего приложения;
- влияние на память, и, следовательно, уменьшает использование батареи на мобильных устройствах;
- размер загруженного файла.
React 16.6.0, выпущенный в октябре 2018 года, представил способ разделения кода, который должен заменить каждый ранее использовавшийся для этого инструмент или библиотеку: React.lazy и Suspense.
React.lazy
и Suspense
образуют идеальный способ ленивой загрузки зависимости по необходимости.
Важно!
React.lazy
и Suspense
пока недоступны для server-side сборки. Для этого лучше использовать Loadable Components. У них есть хорошая документация.
React.lazy
Давайте начнем с React.lazy
. Вы используете его для импорта любого компонента.
Важно!
Синтаксис динамического импорта import()
- это предложение ECMAScript (JavaScript), которое в настоящее время не является частью языкового стандарта. Ожидается, что он будет принят в ближайшее время.
import React from "react";
const TodoList = React.lazy(() => import("./TodoList"));
export default () => {
return (
<div>
<TodoList />
</div>
);
};
компонент TodoList будет динамически добавлен к выводу, как только он станет доступен. Webpack создаст для него отдельный пакет и позаботится о его загрузке при необходимости.
Suspense
Suspense
- это компонент, который можно использовать для обертки любого лениво загруженного компонента:
import React from "react";
const TodoList = React.lazy(() => import("./TodoList"));
export default () => {
return (
<div>
<React.Suspense>
<TodoList />
</React.Suspense>
</div>
);
};
Он заботится об обработке вывода, пока лениво загруженный компонент извлекается и обрабатывается.
Используйте его свойство fallback
для вывода индикатора загрузки:
...
<React.Suspense fallback={<p>Loading...</p>}>
<TodoList />
</React.Suspense>
...
Error boundaries
Если один из модулей не загружается (например, из-за сбоя сети), он вызовет ошибку. Вы можете обработать эти ошибки, чтобы потом понятно отобразить их на UI с помощью Error Boundary. Создав компонент Error Boundary, используйте его в любом месте над ленивыми компонентами для отображения ошибки.
import React from "react";
import MyErrorBoundary from "./MyErrorBoundary";
const TodoList = React.lazy(() => import("./routes/TodoList"));
const NewTodo = React.lazy(() => import("./routes/NewTodo"));
const App = () => (
<div>
<MyErrorBoundary>
<React.Suspense fallback={<p>Loading...</p>}>
<section>
<TodoList />
<NewTodo />
</section>
</React.Suspense>
</MyErrorBoundary>
</div>
);
Разделение кода на основе маршрутов
Вот пример того, как настроить разделение кода на основе маршрутов, используя такие библиотеки, как React Router с React.lazy
.
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
const Home = React.lazy(() => import("./routes/Home"));
const About = React.lazy(() => import("./routes/About"));
const App = () => (
<Router>
<React.Suspense fallback={<p>Loading...</p>}>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/new" component={About} />
</Switch>
</React.Suspense>
</Router>
);
Именной экспорт
React.lazy
в настоящее время поддерживает только экспорт по умолчанию (default exports). Если модуль, который вы хотите импортировать, использует именной экспорт (named exports), вы можете создать промежуточный модуль, который реэкспортирует его по умолчанию.
// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from "react";
const MyComponent = lazy(() => import("./MyComponent.js"));
Источник: Code-Splitting