前言
本文讲述怎么实现动态加载组件,并借此阐述适配器模式。
一、普通路由例子
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。在简单的单页应用中,这样写是ok的。因为打包后的单一js文件bundle.js也不过200k左右,gzip之后,对加载性能并没有太大的影响。
但是,当产品经历多次迭代后,追加的页面导致bundle.js的体积不断变大。这时候,优化就变得很有必要。
二、如何优化
优化使用到的一个重要理念就是——按需加载。
可以结合例子进行理解为:只加载当前页面需要用到的组件。
比如当前访问的是/center页,那么只需要加载Center组件即可。不需要加载Data组件。
业界目前实现的方案有以下几种:
•react-router的动态路由getComponent方法(router4已不支持)
•使用react-loadable小工具库
•自定义高阶组件进行按需加载
而这些方案共通的点,就是利用webpack的code splitting功能(webpack1使用require.ensure,webpack2/webpack3使用import),将代码进行分割。
接下来,将介绍如何用自定义高阶组件实现按需加载。
三、自定义高阶组件
3.1 webpack的import方法
webpack将import()看做一个分割点并将其请求的module打包为一个独立的chunk。import()以模块名称作为参数名并且返回一个Promise对象。
因为import()返回的是Promise对象,所以不能直接给<Router/>使用。
3.2 采用适配器模式封装import()
适配器模式(Adapter):将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
当前场景,需要解决的是,使用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()返回的Promise对象。
当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 修改webpack构建
output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }
在输出项中,增加chunkFilename即可。
四、小结
自定义高阶组件的好处,是可以按最少的改动,来优化已有的旧项目。
像上面的例子,只需要改变import组件的方式即可。花最少的代价,就可以得到页面性能的提升。
其实,react-loadable也是按这种思路去实现的,只不过增加了很多附属的功能点而已。
以上所述是小编给大家介绍的React router动态加载组件之适配器模式的应用,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!
本文向大家介绍Java适配器模式应用之电源适配器功能详解,包括了Java适配器模式应用之电源适配器功能详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Java适配器模式应用之电源适配器功能。分享给大家供大家参考,具体如下: 一、模式定义 存在两种适配器模式 1 对象适配器模式,在这种适配器模式中,适配器容纳一个它包裹的类对象的物理实体。 2 类适配器模式,在这种适配器模式中,适配器继承
本文向大家介绍JavaScript适配器模式详解,包括了JavaScript适配器模式详解的使用技巧和注意事项,需要的朋友参考一下 适配模式可用来在现有接口和不兼容的类之间进行适配,使用这种模式的对象又叫包装器(wrapper),因为它们是在用一个新的接口包装另一个对象。 基本理论 适配器模式:将一个接口转换成客户端需要的接口而不需要去修改客户端代码,使得不兼容的代码可以一起工作。 适配器主要有3
介绍 适配器模式(Adapter)是将一个类(对象)的接口(方法或属性)转化成客户希望的另外一个接口(方法或属性),适配器模式使得原本由于接口不兼容而不能一起工作的那些类(对象)可以一些工作。速成包装器(wrapper)。 正文 我们来举一个例子,鸭子(Dock)有飞(fly)和嘎嘎叫(quack)的行为,而火鸡虽然也有飞(fly)的行为,但是其叫声是咯咯的(gobble)。如果你非要火鸡也要实现
本文向大家介绍java设计模式之适配器模式,包括了java设计模式之适配器模式的使用技巧和注意事项,需要的朋友参考一下 感谢《Android源码设计模式解析与实战》 何红辉 关爱民 著 适配器模式在我们的开发中使用率极高,从代码中随处可见的Adapter就可以判断出来,从最早的ListView、GridView、到现在最新的RecyclerView都需要使用Adapter,并且在开发中我们遇到的
本文向大家介绍Java经典设计模式之适配器模式原理与用法详解,包括了Java经典设计模式之适配器模式原理与用法详解的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了Java经典设计模式之适配器模式。分享给大家供大家参考,具体如下: 适配器模式是把一个类的接口适配成用户所期待的,使得原本由于接口不兼容而不能一起工作的一些类可以在一起工作从而实现用户所期望的功能。 适配器模式的优势: 1. 通过
如何使用适配器模式 横滑的滚动栏理论上应该是这个样子的: 新建一个 Swift 文件:HorizontalScroller.swift ,作为我们的横滑滚动控件, HorizontalScroller 继承自 UIView 。 打开 HorizontalScroller.swift 文件并添加如下代码: @objc protocol HorizontalScrollerDelegate { } 这