[Перевод] React 16.6 Ленивая загрузка (и предварительная загрузка) компонентов

React.js

Описание: Ленивая загрузка (и предварительная загрузка) компонентов в React 16.6

В React 16.6 добавлена ​​новая функция: React.lazy(), которая упрощает разделение кода.

Затем узнайте, как использовать новую функцию React.lazy, и поймите, почему вы должны использовать ее в стандартной демо-версии приложения.

Мы создали веб-приложение для акций, приложение показывает список некоторых акций, нажмите на одну из акций, она покажет недавний график тренда этой акции.

try it

Выше перечислены все функции приложения. ты сможешьGithub RepoПрочитайте исходный код проекта (вы также можете пройти через PR, чтобы просмотреть изменения проекта и рабочие версии для каждого коммита).

В этой статье нас интересует толькоApp.jsКодируйте логику внутри этого файла.

import React from "react";
import StockTable from "./StockTable";

import StockChart from "./StockChart";

class App extends React.Component {
  state = {
    selectedStock: null
  };
  render() {
    const { stocks } = this.props;
    const { selectedStock } = this.state;
    return (
      <React.Fragment>
        <StockTable
          stocks={stocks}
          onSelect={selectedStock => this.setState({ selectedStock })}
        />
        {selectedStock && (
          <StockChart
            stock={selectedStock}
            onClose={() => this.setState({ selectedStock: false })}
          />
        )}
      </React.Fragment>
    );
  }
}

export default App;

AppКомпонент получает данные номенклатуры и отображает<StockTable/>компоненты. Когда одна из акций нажимается для выбора,Appпокажет график для этой акции<StockChart>

В чем проблема?

мы хотимAppЗагружать и отображать как можно быстрее<StockTable />, ноAppНо подождите, пока браузер загрузится (распаковать, проанализировать, скомпилировать, выполнить и т. д.)StockChartкод.

Дисплей можно увидеть через Chrome DevTools<StockTable />Запись прошедшего времени.

Trace without lazy loading

экспонатStockTableВсего 2470 мс (имитация сетевой среды Fast3G и 4-ядерного обычного процессора)

На рисунке ниже видно, что входит в сжатый 125-килобайтный файл, передаваемый в браузер.

Webpack Budle Analyzer Report

Как мы и ожидали, страница загружает реакции, реакции-дом и некоторые зависимости реакции, но страница также загружает зависимости моментов, лодаша и победы зависимостей компонентов. экспонат<StockTable />Эти зависимости не являются обязательными.

Как загрузить зависимости , не влияя на скорость загрузки?

Ленивая загрузка компонентов

Используя «динамический импорт» веб-пакета, мы можем разделить связанный код на две части:mainФайл содержит то, что нужно отобразить<StockTable>код и зависимости. Другой файл содержит отображение<StockChart />код и зависимости.

dynamic importТехнология очень полезная, поэтому в версии React 16.6 добавлен новый API —React.lazy(), что упрощает асинхронное обращение к компонентам React.

Для использования в App.jsReact.lazy(), мы внесли два изменения в код.

Diff

Во-первых, код, который будет статически ссылаться на компонентimport StockChart from "./StockChart"заменен вызовомReact.lazy(),существуетlazy()Пройти в анонимной функции в качестве параметра и динамически представить его в функцииStockChartкомпоненты. Таким образом, браузер не загрузит компонент, пока мы его не отобразим../StockChart.jsфайл и его зависимости.

Если React хочет отображать<StockChart />Когда компонент установлен, что произойдет, если код, от которого зависит компонент, еще не загружен? Вот почему мы добавили<React.Suspense/>. Он будет отображаться до тех пор, пока код не будет загруженfallbackЗначение, переданное атрибутом props, будет отображать содержимое дочернего узла только после того, как будет готов весь код, от которого зависит дочерний узел.

СейчасAppбудет упакован в два файла.

main.jsФайл всего 36 КБ и содержит<StockChart />И его зависимый кодовый файл 89KB.

После оптимизации, как показано на рисунке ниже, в браузере отображается<StockTable />Необходимое время.

!

Браузеру потребовалось 760 мс для загрузкиmain.js(ранее 1250 мс), а выполнение скрипта занимает 61 мс (ранее 487 мс).<StockTable />Заняло всего 1546 мс (ранее 2460 мс).

Preloading — ленивая загрузка компонентов

Теперь мы ускорили загрузку приложения. Но есть еще одна проблема.

Когда пользователь щелкает элемент в первый раз, будут отображаться компоненты резервной схемы «Загрузка…». Это потому чтоAppНужно дождаться загрузки браузера<StockChart />код.

Если мы хотим избежать отображения состояния загрузки, такого как «Загрузка...», нам нужно загрузить код до того, как пользователь щелкнет.

Простой способ реализовать предварительную загрузку кода — заранее вызвать React.lazy().

const stockChartPromise = import("./StockChart");
const StockChart = React.lazy(() => stockChartPromise);

когда мы звонимdynamic imoprt, компонент начинает загружаться и не блокируется<StockTable />Загрузка компонентов.

Взгляните на запись загрузки приложения и сравнение с немодифицированной версией.

Когда пользователь щелкнет элемент в течение 1 с, он увидит «Загрузка...».

Вы также можете оптимизировать ленивую функцию по-своему, чтобы сделать предварительную загрузку компонентов более общей и удобной.

function lazyWithPreload(factory) {
  const Component = React.lazy(factory);
  Component.preload = factory;
  return Component;
}

const StockChart = lazyWithPreload(() => import("./StockChart"));

// somewhere in your component 
...
  handleYouMayNeedToRenderStockChartSoonEvent() {
    StockChart.preload();
  }
...

предварительно визуализированные компоненты

Вышеперечисленных функций уже достаточно для использования демонстрационного приложения. Но для более крупных проектов компонент может также иметь код или данные из других ленивых компонентов до того, как ленивый компонент будет загружен, поэтому пользователю все еще нужно время, чтобы дождаться загрузки компонента.

Еще один способ предварительной загрузки компонента — отрисовка его заранее. Отрисовка компонентов на странице, но не отображение их на странице, то есть скрытая отрисовка.

class App extends React.Component {
  state = {
    selectedStock: null
  };
  render() {
    const { stocks } = this.props;
    const { selectedStock } = this.state;
    return (
      <React.Suspense fallback={<div>Loading...</div>}>
        <StockTable
          stocks={stocks}
          onSelect={selectedStock => this.setState({ selectedStock })}
        />
        {selectedStock && (
          <StockChart
            stock={selectedStock}
            onClose={() => this.setState({ selectedStock: false })}
          />
        )}
        {/* Preload <StockChart/> */}
        <React.Suspense fallback={null}>
          <div hidden={true}>
            <StockChart stock={stocks[0]} />
          </div>
        </React.Suspense>
      </React.Suspense>
    );
  }
}

diff

React загрузится после первого рендеринга приложения.<Stockchart />И попробуйте отрендерить компонент, чтобы также были загружены зависимости или код, необходимый компоненту.

мы будем懒加载组件Завернутая в скрытый div, страница ничего не покажет после загрузки. а также используетсяReact.suspenseзавернуть этоdiv, и этоfallbackзначениеnull, поэтому он не отображается при загрузке.

Примечание:hiddenАтрибут обычно указывает, что узел не имеет значения, и браузер не будет отображать элементы с этим атрибутом. React не выполняет никакой специальной обработки этого свойства (но может обрабатывать скрытые компоненты с более низким приоритетом в будущих версиях).

Что еще?

Последний метод доступен во многих сценариях, но все же имеет некоторые проблемы.

Во-первых, для лениво загруженных компонентов, которые отображаются скрытыми,hiddenСвойства не являются полностью допустимыми. Например, используйтеportalЛениво загруженные компоненты не будут скрыты (вы можете использовать портал, чтобы сделать это без дополнительного div, но это всего лишь хак, и он не будет использоваться в будущем).

Во-вторых, добавляются дополнительные узлы Dom, даже если узлы Dom были скрыты, что может стать проблемой производительности.

Лучший подход — указать React отображать ленивый компонент, но не добавлять его в дерево Dom после загрузки. Но, насколько я понимаю, в текущей версии React это невозможно.

Еще одно улучшение, которое мы можем сделать, — повторно использовать Dom, который мы подготовили при предварительном рендеринге, чтобы, когда пришло время рендерить компонент диаграммы, React не нужно было создавать его снова. Если пользователь собирается нажать на акцию, мы можем отобразить ее с правильными данными до того, как пользователь нажмет (так)

Это все для этой статьи, спасибо за чтение.


Технологический еженедельник IVWEBШок в сети, обратите внимание на публичный номер: сообщество IVWEB, регулярно каждую неделю публикуйте качественные статьи.

  • Сборник статей еженедельника:weekly