React(17)异步组件
26、异步组件
当在React里使用异步组件时,核心知识是两个:
webpack 如何异步加载其他模块:通过 require(['xxx'], function(module){})来实现;
React 里如何使用异步加载的这个模块:参考正常使用模块时的做法;
【异步加载】
关于 webpack 的异步加载,可以查看我写的这一篇异步加载实战DEMO.
简单来说,就是 require 的参数一,从字符串变为数组,然后参数二是一个回调函数,函数的参数,就是你异步加载的模块。
因此 拿到参数 等于 获得模块。
【React里如何使用】
我们要异步获得这个模块;
我们可以参考高阶组件的用法,来使用这个模块(函数返回一个类,赋值给某个变量,然后该变量作为JSX的标签使用);
先给一个简单版本:
class RefsDemo extends React.Component {
constructor() {
super()
this.state = {
myComponent: null
}
this.load = this.load.bind(this)
}
render() {
return <div>
{/* 点击执行 load 方法 */}
<button onClick={this.load}>点击加载异步组件</button>
{/* 变量存在时(非空,使用标签作为JSX的标签名(该变量已被赋值异步模块);否则使用null(即无DOM) */}
{
this.state.myComponent ? <this.state.myComponent></this.state.myComponent> : null
}
</div>
}
load() {
// 这是一个异步行为,所以需要在回调函数里获取这个模块
require(['./learner.js'], Component => {
// 赋值给 state 变量
this.setState({
// 加载到的模块存储在 Comment.default 中(因为是通过 export default 导出的)
myComponent: Component.default
})
})
}
}
思路是:
用 state 变量 myComponent 存储模块,初始为空(不显示也不加载);
当点击按钮时,异步加载模块 './learner.js',回调函数传参获得该模块;
将该模块赋值给 state 变量 myComponent,触发 state 改变时的生命周期(会触发render方法);
render 重新渲染时,发现 this.state.myComponent 隐式转换后非 false,因此使用其 JSX 标签(即将异步组件嵌入到当前组件中);
于是将异步组件嵌入了当前组件中,实现了 React 组件的异步加载;
其他的比较好理解,比较别扭的是 JSX 语法:
{
this.state.myComponent ? <this.state.myComponent></this.state.myComponent> : null
}
之所以可以这么写,参考本系列的 【22】 的第一小节,即组件被赋值给对象的属性时(这里体现的是 this 的 state 属性的 myComponent 属性),因此不需要大写,可以直接用变量名作为标签名。
进阶——异步组件加载器:
问题:
以上的写法还是太过于复杂;
需要用 state 属性来控制组件是否显示;
需要用一个变量存储该模块,并在JSX语法里用这个变量作为标签名;
要写一个 load 方法,用于加载异步组件;
总而言之,不够智能,不优雅;
目标:
写一个异步组件加载器;
实现以下功能:
给其传一个函数,如:const Learner = resolve => require(['./learner.js'], resolve),这个函数的原型是上面的 require(['./learner.js'], Component => {});
再给其传一个变量 displayComponent,用于控制这个组件是否显示;
当第一次设置 displayComponent 为 true,且组件未加载时,则加载该组件;
为了防止组件重复加载,因此组件内部变量 this.state.amount 负责表示当前组件状态(未加载,加载中,加载完毕);
组件何时显示:组件加载完毕(this.state.component) && 父组件控制该组件是否显示(this.state.displayComponent);
因此,父组件只需要干两件事情就行了:
传一个柯里化处理后的异步组件加载函数;
一个变量 displayComponent 控制该异步组件是否显示(首次显示时自动加载);
如
代码:
app.js 父组件内的代码
// 引入异步组件加载器
import AsyncLoad from './asyncLoader.js'
// 异步组件加载函数封装
const Leaner = resolve => require(['./learner.js'], resolve)
// 以下是父组件的 render 方法的异步组件加载器的 JSX 标签
<AsyncLoad modules={Leaner} displayComponent={this.state.displayComponent}></AsyncLoad>
asyncLoader.js 异步组件加载器中的代码
具体解释请看代码注释
/**
* Created by 王冬 on 2018/2/8.
* QQ: 20004604
* weChat: qq20004604
* 异步加载工厂组件
*/
import React from "react";
const loadingStatus = {
notLoaded: 0,
loading: 1,
loaded: 2
}
export default class AsyncLoader extends React.Component {
constructor() {
super()
this.state = {
amount: loadingStatus.notLoaded, // 0 表示未加载,1表示加载中,2表示加载完毕。没有考虑加载失败的问题(并不难)
displayComponent: false, // 是否显示组件
component: null // 异步组件被赋值给这个变量
}
}
// 生命周期函数,父组件更改 state 后会触发这个函数
componentWillReceiveProps(nextProps) {
// 如果没有modules,则直接报错
if (!nextProps.modules) {
return console.error('你没有传值 modules 给【异步组件加载器】')
}
// 如果 control 值为 true,且之前未加载过组件(用 amount === 0 来表示)
if (nextProps.displayComponent && this.state.amount === 0) {
console.log('开始加载组件')
// 那么加载组件
this.setState({
amount: loadingStatus.loading // 表示加载中
})
nextProps.modules(module => {
if (!module.default) {
return console.error('你可能加载多个异步组件,或者加载的组件并非 React 的组件')
}
// 将异步赋值给 state 相应的变量
console.log('组件加载完毕')
this.setState({
amount: loadingStatus.loaded, // 加载完毕
component: module.default
})
})
}
this.setState({
displayComponent: nextProps.displayComponent
})
}
render() {
/* <React.Fragment> 是 React 的包裹容器(类似 Vue 的 <template> 标签) */
return <React.Fragment>
{/* 只有当前显示组件,并且组件加载完毕了,才显示该组件 */}
{
this.state.displayComponent && this.state.component ?
<this.state.component></this.state.component> : null
}
</React.Fragment>
}
}
---------------------
作者:qq20004604
来源:CSDN
原文:https://blog.csdn.net/qq20004604/article/details/79318253
版权声明:本文为博主原创文章,转载请附上博文链接!
React(17)异步组件的更多相关文章
- react中异步组件以及withRouter的使用
什么是异步组件?简单来说就是异步加载一个组件,正常情况浏览器加载的是我们打包好的bundle.js文件,那么这个文件是集合了所有js是代码,然而我们首屏加载并不需要一次性加载所有的组件,这会造成性能的 ...
- React 异步组件
之前写过一篇 Vue 异步组件的文章,最近在做一个简单项目的时候又想用到 React 异步组件,所以简单地了解了一下使用方法,这里做下笔记. 传统的 React 异步组件基本都靠自己实现,自己写一个专 ...
- React 17 要来了,非常特别的一版
写在前面 React 最近发布了v17.0.0-rc.0,距上一个大版本v16.0(发布于 2017/9/27)已经过去近 3 年了 与新特性云集的 React 16及先前的大版本相比,React 1 ...
- React Native 之 组件化开发
前言 学习本系列内容需要具备一定 HTML 开发基础,没有基础的朋友可以先转至 HTML快速入门(一) 学习 本人接触 React Native 时间并不是特别长,所以对其中的内容和性质了解可能会有所 ...
- React Native的组件ListView
React Native的组件ListView类似于iOS中的UITableView和UICollectionView,也就是说React Native的组件ListView既可以实现UITableV ...
- 九、React中的组件、父子组件、React props父组件给子组件传值、子组件给父组件传值、父组件中通过refs获取子组件属性和方法
一.概述 React中的组件: 解决html 标签构建应用的不足. 使用组件的好处:把公共的功能单独抽离成一个文件作为一个组件,哪里里使用哪里引入. [父子组件]:组件的相互调用中,我们把调用者称为父 ...
- React中父子组件数据传递
Vue.js中父子组件数据传递:Props Down , Events Up Angular中父子组件数据传递:Props Down, Events Up React中父子组件数据传递:Prop ...
- react高阶组件的一些运用
今天学习了react高阶组件,刚接触react学习起来还是比较困难,和大家分享一下今天学习的知识吧,另外缺少的地方欢迎补充哈哈 高阶组件(Higher Order Components,简称:HOC) ...
- React 17 All In One
React 17 All In One v17.0.1 https://reactjs.org/blog/2020/10/20/react-v17.html https://reactjs.org/b ...
随机推荐
- Spring Boot与缓存
---恢复内容开始--- JSR-107.Spring缓存抽象.整合Redis 一.JSR107 Java Caching定义了5个核心接口,分别是CachingProvider, CacheMana ...
- nginx简单的命令
nginx -s reload|reopen|stop|quit #重新加载配置|重启|停止|退出 nginx nginx -t #测试配置是否有语法错误 nginx [-?hvVtq] [-s si ...
- C#中的PropertyGrid绑定对象,通过改变某一值而动态设置部分属性的特性
问题:如下,我定义了一个对象,默认设置属性WindowSize ,WindowSize 为不可见,通过改变SaveOnClose的值,动态的改变不可见的属性的显示和隐藏. [DefaultProper ...
- 如何在Linux中轻松删除源安装的软件包?
第1步:安装Stow 在这个例子中,我们使用的是CentOS,因此我们需要扩展的EPEL库.您可以使用以下命令安装它们:yum install epel-release然后,下面这段命令:yum in ...
- ASP.NET Core 2.x On Ubuntu
安装.NET Core 首先需要安装.NET Core Runtime: https://www.microsoft.com/net/download 点击之后,根据您的Linux发行版不同,选择相应 ...
- (简单)华为Nova青春 WAS-AL00的USB调试模式在哪里开启的流程
就在我们使用Pc接通安卓手机的时候,如果手机没有开启usb开发者调试模式,Pc则无办法成功检测到我们的手机,在一些情况下,我们使用的一些功能较强的app好比之前我们使用的一个app引号精灵,老版本就需 ...
- 触发器SQL
CREATE TRIGGER FUEL.HDGJcoaldayexpend1_insertTRIGGER AFTER INSERT ON FUEL.coaldayexpend1 REFERENCING ...
- Day 1 上午
唉,上午就碰到一个开不了机的电脑,白白浪费了半个小时,真的难受QwQ POINT1 枚举 枚举也称作穷举,指的是从问题所有可能的解的集合中一一枚举各元素. 用题目中给定的检验条件判定哪些是无用的,哪些 ...
- 第二篇--PCI设备解析
介绍:参考 一个系统上最多有256个PCI总线,每个总线最多有32个设备,每个设备最多有8个功能,每个功能最多有256字节的配置地址空间,所以总的配置地址空间是16M. PCI设备有物理设备和逻辑设备 ...
- Redisson分布式锁实现
转: Redisson分布式锁实现 2018年09月07日 15:30:32 校长我错了 阅读数:3303 转:分布式锁和Redisson实现 概述 分布式系统有一个著名的理论CAP,指在一个分布 ...