предисловие
В этой статье описывается, как реализовать динамически загружаемые компоненты, и объясняется шаблон адаптера.
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
Он также реализован таким образом, но только добавляет много вспомогательных функциональных точек.
Ссылаться на
- Загрузка компонентов реакции по запросу на основе разделения кода веб-пакета
- Реализация асинхронной загрузки компонентов с помощью import() webpack2 в реакции
Друзья, которым нравятся мои статьи, могут подписаться на меня следующими способами:
- "звезда"или"смотреть"мойGitHub blog
- RSS-канал моего личного блога:База мистера Вана