React lazy что это
Ленивая загрузка в React
React использует такие сборщики, как WebPack, для упаковки своего кода и его развертывания в браузере. Этот пакет используется браузером для визуализации вашего приложения React.
Теперь представьте, что вы создаете приложение с сотнями компонентов. По умолчанию, упаковщик объединит все эти компоненты в один bundle.js и загрузит ваше приложение. Это, в свою очередь, увеличит первоначальный размер бандла, что приведет к увеличению времени загрузки.
Существует так называемое правило 3х секунд, которое гласит, что для привлечения внимания потребителя требуется примерно 3 секунды. Таким образом, если загрузка занимает больше времени, клиент / пользователь может даже не остаться, чтобы проверить конечный продукт, скорее он может потратить больше времени на поиск альтернативы.
Так, что мы можем сделать, чтобы улучшить нашу работу и не заставлять нашего клиента ждать?
Ответ прост: сначала загрузите компоненты, которые требуются, и, когда потребуются, загрузите остальные. Это и есть ленивая загрузка, загрузка приложения по частям, а не одним пакетом.
Подумайте об этом, у вас есть приложение со следующей структурой:
По умолчанию, когда вы загружаете React приложение, оно загружает все компоненты одновременно. Но требуются ли нам компоненты User Dashboard и Logout, когда пользователь даже не вошел в систему. Первыми мы можем загрузить только компоненты Home и Login / Register, и это уменьшит размер вдвое, увеличив время загрузки. Когда пользователь входит в приложение, мы можем загрузить два других компонента.
Теперь мы знаем, почему давайте начнем с того, КАК?
В этой статье я покажу вам два способа реализации отложенной загрузки
Я предполагаю, что вы обладаете базовыми знаниями о React и перейдете непосредственно к реализации.
У меня есть основной компонент App.js, в котором я буду определять два маршрута:
Использование React.lazy и Suspense
Эта функция была впервые представлена в React версии 16.6.0, чтобы обеспечить ленивую загрузку в экосистеме.
Пока не поддерживается при рендеринге на стороне сервера.
В React мы используем ключевое слово import для извлечения компонента, который в основном является модулем JavaScript.
По умолчанию импорт извлекает модуль и объединяет его в файл пакета. Нам требуется импорт, который по своей природе более динамичен, то есть импорт происходит только тогда, когда это требуется.
React.lazy делает возможным этот динамический импорт, который также прост в реализации.
На данный момент React.lazy не поддерживает именованные экспорты, поэтому не забудьте использовать экспорт по умолчанию для компонентов, которые вы хотите динамически импортировать.
Как только модуль загружен, он вернет новый пакет с Компонентом, объединенным с предыдущим кодом.
Этот обновленный пакет также обновляется в кеше, то есть после загрузки компонента веб-пакет не будет пытаться импортировать тот же компонент снова.
Как указано выше, динамический импорт возвращает обещание, что означает, что требуется время, чтобы получить модуль, обновить пакет и загрузить необходимый компонент. Поэтому нам может понадобиться резервный контент, который будет отображаться во время загрузки компонента, и именно здесь нам понадобится Suspense.
Во-первых, нам нужно импортировать модуль Suspense из React:
Компонент входа отображается с использованием React.lazy и Suspense
Чтобы проверить, работают ли наши изменения или нет, мы можем проверить dev-tools:
1.chunk вызывается, когда компонент динамически импортируется
Мы также можем определить отоборажение ошибок в Suspense для обработки пользовательских ошибок, если компонент не загружается.
Создание своего собственного HOC
Создавая наш собственный компонент высшего порядка для загрузки компонентов, мы получаем свободу вносить любые изменения по мере необходимости.
Давайте посмотрим на вызов этого HOC, вы можете увидеть сходство вызывающих методов с методом React.lazy.
Компонент Register, отображаемый с использованием нашего пользовательского HOC
Как и в приведенном выше примере, давайте проверим dev-tools: 2
2.chunk загружается
Как мы видим, когда был вызван компонент Register, был отправлен новый чанк с обновленным пакетом.
Вы можете найти репозиторий для приведенного выше примера здесь.
React.lazy? Но что если у вас не компонент?
Этот code splitting, честное слово, уже немного надоел. Мы все ходим и ходим по кругу, и в этом и есть главная проблема.
Code splitting начинался как разделение на уровне Модулей, а закончился как разделение на уровне Компонент.
И проблема тут исключительно в голове — React.lazy это хорошо, но и import никуда не делся… Так почему же code splitting только про компоненты?
React.lazy, React-Loadable, Loadable-Components, Imported-component — на свете много библиотек, которые оборачивают загрузку модуля в некий сахар, исключительно чтобы немного более user-friendly обработать загрузку компонента и показать его по готовности. Минимальный код для «async-loader».
Suspense и React.lazy просто другой вариант работы со стейтом. Ничего более.
Но что делать если у вас не компонент?
Проблемы с этим вроде бы нет — import(«someStuff»).then(‘go-on’). Но тут опять начинаются вопросы про то как это правильно разместить в lifecycle Reactа, что делать есть промис заресолвился после смерти компонента, и так далее. И всех в голове одни компоненты.
Я провел мини опрос — НИКТО более не использует этот, самый древний, вариант code splitting. Не знает как его кушать в современных условиях. И в общем все плохо.
При этом решение есть, и опять же в 4 строчки — renderProps
Все очень просто — не смотря на то, что обьектом code splitting будет не Компонент а Модуль — местом совершения операции всеравно будет Компонент.
Тот же самый паттерн, только повернутый в сторону загрузки кода и «предоставления» этого кода как renderProps.
Работает из коробки:
Дешево, и очень сердито. Мне это позволило срезать дополнительные 20%. Но, главное, позволило очень декларативно настроить code-splitting, который будет загружать только то, что надо, и когда надо.
Теперь твой ход, %username%.
И кто перепишет это на hooks?
Как использовать React.lazy и Suspense для отложенной загрузки компонентов
Дата публикации: 2018-12-18
От автора: React 16.6 вывел разделение кода на новый уровень. Теперь вы можете загружать компоненты, когда это действительно необходимо, без установки дополнительных библиотек.
Что такое разделение кода и отложенная загрузка?
Webpack определяет разделение кода как: «Метод разделения вашего кода на различные пакеты, которые затем могут быть загружены по требованию или параллельно».
Другой способ сказать: «загрузка по требованию или параллельно» — это отложенная загрузка. Противоположностью отложенной загрузке являются прямая загрузка. При ней все загружается независимо от того, используете вы это или нет.
Для чего использовать разделение кода и отложенную загрузку?
Иногда нам приходится вводить большой фрагмент кода для реализации некоторых функций. Этот код может импортировать стороннюю зависимость или записывать ее самостоятельно. Этот код влияет на размер основного пакета.
Загрузка нескольких мегабайт — это пустяки для сегодняшней интернет-скорости. Но нам по-прежнему приходится думать о пользователях с медленным подключением к Интернету или пользователях мобильных устройств.
Изучите основы ReactJS на практическом примере по созданию учебного веб-приложения
Как это было до React 16.6?
Вероятно, самая популярная библиотека React для отложенной загрузки компонентов — react-loadable. Важно, что responsejs.org по-прежнему рекомендует react-loadable, если ваше приложение визуализируется на сервере. react-loadable на самом деле очень похож на новый подход React. Я покажу это в следующем примере.
Что-нибудь нужно для настройки?
Хорошо, нам требуется Webpack, который обрабатывает динамический импорт пакетов. Приведенная ниже демо-версия сгенерирована Create React App. И в этом случае Webpack уже настроен, и мы готовы к работе.
Демо-версия
Для этой демо-версии мы будем использовать react-pdf. react-pdf — это удивительная библиотека, используемая для создания PDF-файлов в браузере, на мобильных устройствах и на сервере. Мы могли бы создать PDF-файл на сервере, но если мы сделаем это на стороне клиента, размер пакетов будет меньше.
Я использую расширение для Visual Studio Code Import cost, чтобы увидеть размеры используемых библиотек. Скажем, нам нужно, чтобы, когда пользователь нажимает кнопку, генерировался PDF-файл.
Теперь это простая форма с одним вариантом использования. Попытайтесь представить себе огромное веб-приложение, в котором это является небольшой частью функционала. Возможно, эта функция не очень часто используется пользователями.
Давайте представим себе эту ситуацию. Генерация PDF не используется очень часто, и нет смысла загружать весь код для каждого запроса страницы.
Я попытаюсь показать, как мы можем разработать решение с отложенной загрузкой и без нее.
Примеры прямой и отложенной загрузки
В обоих случаях мы будем использовать один компонент, который импортирует зависимости react-pdf и создает простой PDF-документ.
Code-Splitting
Most React apps will have their files “bundled” using tools like Webpack, Rollup or Browserify. Bundling is the process of following imported files and merging them into a single file: a “bundle”. This bundle can then be included on a webpage to load an entire app at once.
Bundle:
Your bundles will end up looking a lot different than this.
If you’re using Create React App, Next.js, Gatsby, or a similar tool, you will have a Webpack setup out of the box to bundle your app.
If you aren’t, you’ll need to set up bundling yourself. For example, see the Installation and Getting Started guides on the Webpack docs.
Bundling is great, but as your app grows, your bundle will grow too. Especially if you are including large third-party libraries. You need to keep an eye on the code you are including in your bundle so that you don’t accidentally make it so large that your app takes a long time to load.
To avoid winding up with a large bundle, it’s good to get ahead of the problem and start “splitting” your bundle. Code-Splitting is a feature supported by bundlers like Webpack, Rollup and Browserify (via factor-bundle) which can create multiple bundles that can be dynamically loaded at runtime.
Code-splitting your app can help you “lazy-load” just the things that are currently needed by the user, which can dramatically improve the performance of your app. While you haven’t reduced the overall amount of code in your app, you’ve avoided loading code that the user may never need, and reduced the amount of code needed during the initial load.
The best way to introduce code-splitting into your app is through the dynamic import() syntax.
Before:
After:
When Webpack comes across this syntax, it automatically starts code-splitting your app. If you’re using Create React App, this is already configured for you and you can start using it immediately. It’s also supported out of the box in Next.js.
If you’re setting up Webpack yourself, you’ll probably want to read Webpack’s guide on code splitting. Your Webpack config should look vaguely like this.
When using Babel, you’ll need to make sure that Babel can parse the dynamic import syntax but is not transforming it. For that you will need @babel/plugin-syntax-dynamic-import.
React.lazy and Suspense are not yet available for server-side rendering. If you want to do code-splitting in a server rendered app, we recommend Loadable Components. It has a nice guide for bundle splitting with server-side rendering.
The React.lazy function lets you render a dynamic import as a regular component.
Before:
After:
This will automatically load the bundle containing the OtherComponent when this component is first rendered.
The lazy component should then be rendered inside a Suspense component, which allows us to show some fallback content (such as a loading indicator) while we’re waiting for the lazy component to load.
The fallback prop accepts any React elements that you want to render while waiting for the component to load. You can place the Suspense component anywhere above the lazy component. You can even wrap multiple lazy components with a single Suspense component.
If the other module fails to load (for example, due to network failure), it will trigger an error. You can handle these errors to show a nice user experience and manage recovery with Error Boundaries. Once you’ve created your Error Boundary, you can use it anywhere above your lazy components to display an error state when there’s a network error.
Route-based code splitting
Deciding where in your app to introduce code splitting can be a bit tricky. You want to make sure you choose places that will split bundles evenly, but won’t disrupt the user experience.
A good place to start is with routes. Most people on the web are used to page transitions taking some amount of time to load. You also tend to be re-rendering the entire page at once so your users are unlikely to be interacting with other elements on the page at the same time.
5 приемов по разделению «бандла» и «ленивой» загрузке компонентов в React
Разделение Javascript-кода на несколько файлов называется разделением «бандла» или сборки (bundle splitting). Это позволяет загружать только тот код, который который используется приложением в данный момент, другие части загружаются по необходимости (по запросу пользователя).
Распространенные случаи разделения сборки и «ленивой» или отложенной загрузки (lazy loading) включают в себя следующее:
Загрузка дополнительного кода при переходе пользователя к новому представлению (view — слой, отвечающий за визуальное отображение)
Загрузка такого кода может быть связана с определенным действием, таким как прокрутка или нажатие кнопки
Также можно реализовать предварительную загрузку определенных ресурсов, которые представляют потенциальный интерес для пользователя
Это приводит к тому, что когда пользователь захочет получить доступ к определенной функциональности, она уже будет готова
1. Динамический импорт с помощью Webpack
Webpack позволяет загружать модули (компоненты) динамически во время выполнения кода. Рассмотрим пример:
Динамический импорт может использоваться в любом месте кода. Такой импорт сообщает Webpack о необходимости создания отдельной сборки для конкретного компонента. Поскольку модальное окно отображается только когда пользователь нажимает кнопку, мы можем отложить загрузку соответствующего кода.
Динамический импорт позволяет каждому компоненту выступать в роли микрофронтенда (microfrontend).
2. Split API для загрузки React-компонентов
Резервного компонента при возникновении ошибки
«Настоящего» компонента после загрузки сборки
Рассматриваемый интерфейс облегчает задачу разделения React-компонентов, позволяя избежать повторения шаблонного кода.
Разделение компонентов верхнего уровня на основе маршрутов — еще одна техника оптимизации, способ уменьшения времени загрузки приложения.
В целом, отложенная загрузка кода до запроса пользователем страницы по конкретному маршруту — это хорошая идея.
В данном случае мы также имеем возможность использовать динамический импорт.
3. Создание «вендорного бандла» (vendor bundle)
Прежде всего, вы можете спросить, для чего нам это нужно? Основная идея заключается в том, что в вендор помещается (выносится) код, который изменяется намного реже, чем код разрабатываемого приложения. Это позволяет использовать эффективные техники по кэшированию кода для повышения скорости загрузки страниц.
Вот как можно извлечь вендорный бандл из директории node_modules :
Если после этого вы запустите сборку ( yarn build или npm run build ), то увидите что-то вроде этого:
4. Создание нескольких вендорных бандлов
Обычно, все модули объединяются в один вендорный бандл.
Знаете ли вы, что мы можем создать несколько таких бандлов?
Например, поскольку React не будет меняться между сборками, имеет смысл закэшировать его в виде отдельного пакета в случаях, когда вопрос производительности является критически важным.
5. Ленивая загрузка компонентов с помощью React.lazy()
React.lazy() — это функция, позволяющая рендерить динамически импортируемые компоненты как обычные компоненты.
Динамический импорт с помощью React.lazy() :
Проп fallback принимает любой элемент (компонент). Компонент Suspense может быть помещен на любом родительском по отношению к «ленивому» компоненту уровне.
Suspense может оборачивать как отдельный компонент, так и группу компонентов:
Заключение
После применения техник, названных в данной статье, при анализе производительности вашего приложения, вы увидите два главных улучшения. Уменьшение размера сборки, загружаемой при инициализации приложения, и увеличение количества сборок, загружаемых по необходимости.
Это, безусловно, положительно повлияет на пользовательский опыт работы с приложением, поскольку оно станет более быстрым и отзывчивым.
Также не стоит забывать о том, что загруженный JavaScript-код, должен быть разобран и выполнен, что также требует некоторого времени и вычислительной мощности.
Облачные серверы от Маклауд быстрые и безопасные.
Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!