之前写过一篇 Vue 异步组件的文章,最近在做一个简单项目的时候又想用到 React 异步组件,所以简单地了解了一下使用方法,这里做下笔记。

传统的 React 异步组件基本都靠自己实现,自己写一个专门的 React 组件加载函数作为异步组件的实现工具,通过 import() 动态导入,实现异步加载,可以参考【翻译】基于 Create React App路由4.0的异步组件加载(Code Splitting)这篇文章。这样做的话还是要自己写一个单独的加载组件,有点麻烦。于是想找个更简单一点的方式,没想到真给找到了:Async React using React Router & Suspense,这篇文章讲述了如何基于 React Router 4 和 React 的新特性快速实现异步组件按需加载。

2018 年 10 月 23 号,React 发布了 v16.6 版本,新版本中有个新特性叫 lazy,通过 lazy 和 Suspense 组件我们就可以实现异步组件,如果你使用的是 React v16.6 以上版本:

最简单的实现方法:

// codes from https://react.docschina.org

import React, { lazy, Suspense } from 'react';
const OtherComponent = lazy(() => import('./OtherComponent')); function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
);
}

从 React 中引入 lazy 方法和 Suspense 组件,然后用 lazy 方法处理我们的组件,lazy 会返回一个新的React 组件,我们可以直接在 Suspense 标签内使用,这样组件就会在匹配的时候才加载。

lazy 接受一个函数作为参数,函数内部使用 import() 方法异步加载组件,加载的结果返回。

Suspense 组件的 fallback 属性是必填属性,它接受一个组件,在内部的异步组件还未加载完成时显示,所以我们通常传递一个 Loading 组件给它,如果没有传递的话,就会报错。

所以在使用 React Router 4 的时候,我们可以这样写:

import React, { lazy, Suspense } from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom'; const Index = lazy(() => import('components/Index'));
const List = lazy(() => import('components/List')); class App extends React.Component {
render() {
return <div>
<HashRouter>
<Suspense fallback={Loading}>
<Switch>
<Route path="/index" exact component={Index}/>
<Route path="/list" exact component={List}/>
</Switch>
</Suspense>
</HashRouter>
</div>
}
} function Loading() {
return <div>
Loading...
</div>
} export default App;

在某些 React 版本中,lazy 函数还有 bug,会导致 React Router 的 component 属性接受 lazy 函数返回结果时报错:React.lazy makes Route's proptypes fail

我也遇到了这种 bug,具体的依赖版本如下:

"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-router-dom": "^4.3.1"

首次安装依赖后就再也没有更新过,所以小版本应该也是上面的小版本,不存在更新。

解决方法可以把 lazy 的结果放在函数的返回结果中:

import React, { lazy, Suspense } from 'react';
import { HashRouter, Route, Switch } from 'react-router-dom'; const Index = lazy(() => import('components/Index'));
const List = lazy(() => import('components/List')); class App extends React.Component {
render() {
return <div>
<HashRouter>
<Suspense fallback={Loading}>
<Switch>
<Route path="/index" exact component={props => <Index {...props}/>}/>
<Route path="/list" exact component={props => <List {...props}/>}/>
</Switch>
</Suspense>
</HashRouter>
</div>
}
} function Loading() {
return <div>
Loading...
</div>
} export default App;

上面代码和之前唯一的不同就是把 lazy 返回的组件包裹在匿名函数中传递给 Route 组件的 component 属性。

这样我们的组件都会在路由匹配的时候才开始加载,Webpack 也会自动代码进行 code split,切割成很多小块,减小了首页的加载时间以及单独一个 js 文件的体积。在工作中已经实践过了,确实好用:

如果没有使用 React v16.6 以上版本,也可以自己实现,我们可以写一个专门用于异步加载的函数:

function asyncComponent(importComponent) {
class AsyncComponent extends React.Component {
render() {
return this.state.component;
}
state = {
component: null
}
async componentDidMount() {
const { default: Component } = await importComponent();
this.setState({
component: <Component {...this.props}/>
});
}
}
return AsyncComponent;
}

使用的方法与 React.lazy 相同,传入一个异步加载的函数即可,上面这个函数需要注意的地方就是 import() 进来的组件被包裹在 default 属性里,结构时要用 const { default: Component } = ... 这种形式。

效果如下:

总的来说:

  • 新版 React 使用起来更加简便~
  • 异步组件按需加载这些操作都是基于打包工具的特性,比如 Webpack 的 import

React 异步组件的更多相关文章

  1. react异步加载组件

    1. 创建 asyncComponent 异步加载工具 import React from 'react' function asyncComponent(loadComponent){ class ...

  2. React(17)异步组件

    26.异步组件当在React里使用异步组件时,核心知识是两个: webpack 如何异步加载其他模块:通过 require(['xxx'], function(module){})来实现:React ...

  3. react中异步组件以及withRouter的使用

    什么是异步组件?简单来说就是异步加载一个组件,正常情况浏览器加载的是我们打包好的bundle.js文件,那么这个文件是集合了所有js是代码,然而我们首屏加载并不需要一次性加载所有的组件,这会造成性能的 ...

  4. beeshell —— 开源的 React Native 组件库

    介绍 beeshell 是一个 React Native 应用的基础组件库,基于 0.53.3 版本,提供一整套开箱即用的高质量组件,包含 JavaScript(以下简称 JS)组件和复合组件(包含 ...

  5. react第二单元(react的组件-state-props-setState)

    第二单元(react的组件-state-props-setState) 课程目标 理解组件和组件的创建.以及能够根据实际场景去划分合理的组件. 理解并且能够灵活的应用组件中的state.props. ...

  6. 移动web端的react.js组件化方案

     背景: 随着互联网世界的兴起,web前端开发的方式越来越多,出现了很多种场景开发的前端架构体系,也对前端的要求日益增高,早已经不是靠一个JQuery.js来做前端页面的时代了,而今移动端变化最大,近 ...

  7. Griddle, griddle-react 一个REACT 表格组件

    Griddle, griddle-react 一个REACT 表格组件: http://griddlegriddle.github.io/Griddle/index.html

  8. React Native组件之Text

    React Native组件之Text相当于iOS中的UILabel. 其基本属性如下: /** * Sample React Native App * https://github.com/face ...

  9. React Native组件之Switch和Picker和Slide

    React Native组件Switch类似于iOS中的UISwitch:组件Slide类似于iOS中UIslider,组件Picker类似于iOS的UIPickerView.他们的使用方法和相关属性 ...

随机推荐

  1. 如何编写makefile文件

    最近一直在学习makefile是如何编写的.       当我们写的程序文件比较少的时候,敲入gcc /g++,当你在大型工程中,在一个个编译文件的话,你可能就会很郁闷.linux有一个自带的make ...

  2. 我用ASP.NET缓存之数据缓存

    [我的理解] Cache,是内置的对象集合.是全局的,类似于static Arraylist.它是线程安全的,添加或修改Cache中的项目时,不需要锁定或者解除Cache. 添加 Cache[Key] ...

  3. Tomcat启动项目两次

    网上一搜,给出的答案都一样,不外乎:1.删除 Host 标签配置的 appBase="webapps"2.删除 Context 配置 此处这样做:重新添加Tomcat,选择好自己的 ...

  4. JAVA虚拟机的生命周期

    一个运行时的Java虚拟机实例的天职是:负责运行一个java程序.当启动一个Java程序时,一个虚拟机实例也就诞生了.当该程序关闭退出,这个虚拟机实例也就随之消亡.如果同一台计算机上同时运行三个Jav ...

  5. SpringMVC+MyBatis+MySQL 8小时链接断开

    org.springframework.web.util.NestedServletException: Request processing failed; nested exception is ...

  6. [js常用]连续播放音频

    许多音频连续播放.有的时候音频过大会分成多个音频.播放的时候需要连续播放 <!DOCTYPE HTML> <html> <head> <meta charse ...

  7. html History API

    History api 兼容性支持一下浏览器 为什么要使用History API 在AJAX给我们带来提高用户体验.减少HTTP连接数等好处的同时,也渐渐显露出一些不足之处,比如: 1.页面全是用aj ...

  8. RESULT_OK,RESULT_CANCELED,RESULT_FIRST_USER

    RESULT_OK是执行结果,有RESULT_OK,RESULT_CANCELED,RESULT_FIRST_USER 在调用系统app时返回时RESULT_CANCELED如字面意思代表取消,RES ...

  9. spring多线程初探

    6月14号  晴  最高温度37   今天很热的一天啊,开发的任务现在正在测试阶段,手头没有什么工作任务,忙里偷闲,丰富一下我的blog. 前两天有个需求:调用第三方接口,这个接口的响应时间有点长,需 ...

  10. MOTT介绍(2)window安装MQTT服务器和client

    MQTT目录: MQTT简单介绍 window安装MQTT服务器和client java模拟MQTT的发布,订阅 window安装MQTT服务器,我这里下载了一个apache-apollo-1.7.1 ...