博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React router动态加载组件-适配器模式的应用
阅读量:4086 次
发布时间:2019-05-25

本文共 3329 字,大约阅读时间需要 11 分钟。

前言

本文讲述怎么实现动态加载组件,并借此阐述适配器模式。

一、普通路由例子

import Center from 'page/center';import Data from 'page/data';function App(){    return (        
(
)} />

页面不见了

} />
);}

以上是最常见的 React router 。在简单的单页应用中,这样写是ok的。因为打包后的单一js文件 bundle.js 也不过200k左右, gzip 之后,对加载性能并没有太大的影响。

但是,当产品经历多次迭代后,追加的页面导致 bundle.js 的体积不断变大。这时候,优化就变得很有必要。

二、如何优化

优化使用到的一个重要理念就是—— 按需加载 。

可以结合例子进行理解为:只加载当前页面需要用到的组件。

比如当前访问的是 /center 页,那么只需要加载 Center 组件即可。不需要加载 Data 组件。

业界目前实现的方案有以下几种:

  • react-router的动态路由 getComponent 方法(router4已不支持)
  • 使用  小工具库
  • 自定义高阶组件进行按需加载

而这些方案共通的点,就是利用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 
'); /*eslint-enable*/ throw error; }) } hasLoadedComponent() { return this.state.Component !== null; } render(){ const { Component } = this.state; return (Component) ?
: 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 也是按这种思路去实现的,只不过增加了很多附属的功能点而已。

参考

转载地址:http://dvgni.baihongyu.com/

你可能感兴趣的文章
platform_driver平台驱动注册和注销过程(下)
查看>>
.net强制退出主窗口的方法——Application.Exit()方法和Environment.Exit(0)方法
查看>>
c# 如何调用win8自带的屏幕键盘(非osk.exe)
查看>>
build/envsetup.sh 简介
查看>>
linux怎么切换到root里面?
查看>>
安装alien,DEB与RPM互换
查看>>
编译Android4.0源码时常见错误及解决办法
查看>>
Android 源码编译make的错误处理
查看>>
linux环境下C语言中sleep的问题
查看>>
ubuntu 12.04 安装 GMA3650驱动
查看>>
新版本的linux如何生成xorg.conf
查看>>
xorg.conf的编写
查看>>
启用SELinux时遇到的问题
查看>>
virbr0 虚拟网卡卸载方法
查看>>
No devices detected. Fatal server error: no screens found
查看>>
新版本的linux如何生成xorg.conf
查看>>
Centos 6.0_x86-64 终于成功安装官方显卡驱动
查看>>
Linux基础教程:CentOS卸载KDE桌面
查看>>
read humor_campus
查看>>
IBM WebSphere Commerce Analyzer
查看>>