Маршрутизатор React динамически загружает компоненты — применение режима адаптера

внешний интерфейс React.js Promise Webpack

предисловие

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

1. Общий пример маршрутизации

import Center from 'page/center';
import Data from 'page/data';

function App(){
    return (
        <Router>
          <Switch>
            <Route exact path="/" render={() => (<Redirect to="/center" />)} />
            <Route path="/data" component={Data} />
            <Route path="/center" component={Center} />
            <Route render={() => <h1 style={{ textAlign: 'center', marginTop: '160px', color:'rgba(255, 255, 255, 0.7)' }}>页面不见了</h1>} />
          </Switch>
        </Router>
    );
}

Вышеперечисленные являются наиболее распространеннымиReact router. В простых одностраничных приложениях это нормально писать. Поскольку упакованный один файл jsbundle.jsЭто всего около 200к,gzipПосле этого на загрузочную способность сильно не влияет.
Однако, когда продукт проходит несколько итераций, добавленные страницы вызываютbundle.jsобъем продолжает увеличиваться. В это время становится необходимой оптимизация.

2. Как оптимизировать

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

Например, текущий доступ/centerстраницу, затем просто загрузитеCenterкомпоненты. Нет необходимости загружатьDataкомпоненты.

В настоящее время в отрасли реализованы следующие решения:

  • Динамическая маршрутизация для реактивного маршрутизатораgetComponentметод (router4 больше не поддерживается)
  • использоватьreact-loadableбиблиотека гаджетов
  • Пользовательские компоненты высшего порядка для загрузки по требованию

Общим моментом этих решений является использование webpackcode splittingФункция(webpack1 используетrequire.ensure, WebPack2 / WebPack3 используетimport), чтобы разделить код.

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

3. Пользовательские компоненты высокого порядка

3.1 Метод импорта веб-пакета

вебпак будетimport()Думайте об этом как о точке разделения и упакуйте запрошенные модули в отдельный фрагмент.import()принимает имя модуля в качестве имени параметра и возвращаетОбъект обещания.

потому чтоimport()То, что возвращается, является объектом Promise, поэтому его нельзя передать напрямую.<Router/>использовать.

3.2 Инкапсуляция import() в режиме адаптера

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

В текущем сценарии необходимо решить, как использоватьimport()После того, как компонент загружен асинхронно, как передать загруженный компонент в React для обновления.
Метод также очень прост в использованииstate. Когда компонент загружается асинхронно, вызовитеsetStateспособ уведомления.
Затем, согласно этой идее, создайте новый высокоуровневый компонент и используйте适配器模式, Ну давай жеimport()инкапсулировать.

3.3 Реализуйте метод асинхронной загрузки asyncComponent

import React from 'react';

export const asyncComponent = loadComponent => (

    class AsyncComponent extends React.Component {
        constructor(...args){
            super(...args);
    
            this.state = {
                Component: null,
            };

            this.hasLoadedComponent = this.hasLoadedComponent.bind(this);
        }
        componentWillMount() {
            if(this.hasLoadedComponent()){
                return;
            }
    
            loadComponent()
                .then(module => module.default ? module.default : module)
                .then(Component => {
                    this.setState({
                        Component
                    });
                })
                .catch(error => {
                    /*eslint-disable*/
                    console.error('cannot load Component in <AsyncComponent>');
                    /*eslint-enable*/
                    throw error;
                })
        }
        hasLoadedComponent() {
            return this.state.Component !== null;
        }
        render(){
            const {
                Component
            } = this.state;

            return (Component) ? <Component {...this.props} /> : null;
        }
    }
);

// 使用方式 

const Center = asyncComponent(()=>import(/* webpackChunkName: 'pageCenter' */'page/center'));

Как показано в примере, создайте новыйasyncComponentспособ полученияimport()Обещаю вернуть объект.
когдаcomponentWillMountКогда (рендеринг на стороне сервера также имеет этот метод жизненного цикла), выполнитеimport(), и загрузит компонент асинхронно,setвойтиstate, который запускает повторную визуализацию компонента.

3.4 Устранение сомнений

  • Инициализация state.Component
this.state = {
    Component: null,
};

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

  • module.default ? module.default : module

вот для совместимости具名а такжеdefaultдваexportнаписание.

  • return (Component) ? <Component {...this.props} /> : null;

здесьnull, вы действительно можете использовать<LoadingComponent />заменять. Функция такова: когда асинхронный компонент не загружен, он действует как заполнитель.
this.propsчерезAsyncComponentКомпонент прозрачно передается асинхронному компоненту.

3.5 Изменение сборки веб-пакета

output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
}

В элементе вывода добавьтеchunkFilenameВот и все.

4. Резюме

Преимущество пользовательских компонентов более высокого порядка заключается в том, что вы можете оптимизировать существующие устаревшие проекты с минимальными изменениями.
Как и в примере выше, просто изменитеimportкомпонентный способ. С наименьшими затратами вы можете получить улучшение производительности страницы.
фактически,react-loadableОн также реализован таким образом, но только добавляет много вспомогательных функциональных точек.

Ссылаться на

  1. Загрузка компонентов реакции по запросу на основе разделения кода веб-пакета
  2. Реализация асинхронной загрузки компонентов с помощью import() webpack2 в реакции

Друзья, которым нравятся мои статьи, могут подписаться на меня следующими способами: