博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[译] React 16.6 懒加载(与预加载)组件
阅读量:7097 次
发布时间:2019-06-28

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

React 16.6添加了一个新的特性: React.lazy(), 它可以让代码分割(code splitting)更加容易。

接下来通过一个股票App Demo, 来学习如何使用React.lazy这个新特性并了解为什么要使用它。

我们创建了一个股票Web App,App展示了一些股票的列表,点击其中的一个股票,它会展示出最近这只股票的走势图。

以上就是App的全部功能了。 你可以在阅读项目源码(也可以通过PR,查看每一次提交的项目变更和可运行版本。)

在本文,我们只关心App.js这个文件内的代码逻辑。

import React from "react";import StockTable from "./StockTable";import StockChart from "./StockChart";class App extends React.Component {  state = {    selectedStock: null  };  render() {    const { stocks } = this.props;    const { selectedStock } = this.state;    return (      
this.setState({ selectedStock })} /> {selectedStock && (
this.setState({ selectedStock: false })} /> )}
); }}export default App;复制代码

App组件获取股票列表的数据并且展示了<StockTable/>组件。当其中一个股票被点击选中时, App将会展示那只股票的走势图<StockChart>

这里有什么问题呢?

我们想要App尽可能快速加载与展示<StockTable />, 但App却要等待浏览器下载(解压, 分析, 编译, 执行等)StockChart的代码。

通过Chrome DevTools可以看到展示<StockTable />所消耗的时间记录。

展示StockTable一共耗时2470ms(模拟Fast3G网络环境与4核普通CPU)

通过下图,可以了解到在向浏览器传输压缩后的125K文件中都包含了什么

如我们所预期,页面加载了react, react-dom 和一些react的依赖包,但页面也同时加载了组件依赖的moment, lodash, victory的依赖。展示<StockTable />是不需要这些依赖的。

那如何加载 <StockChart />的依赖才不会影响的加载速度呢?

懒加载组件

通过使用webpack的'dynamic import', 我们可以将打包的代码拆分成两部分,main文件里包含了需要展示<StockTable>的代码及依赖。另一个文件包含了展示<StockChart />的代码及依赖包。

dynamic import技术是十分有用的,所以React16.6版本新添加了一个API - React.lazy(), 可以更便利地去异步引用React组件。

为了在App.js中使用React.lazy(), 我们在代码中做了两处变更。

首先,将静态引用组件的代码import StockChart from "./StockChart"替换为调用React.lazy(),在lazy()传入一个匿名函数作为参数,在函数中动态引入StockChart组件。这样在我们渲染这个组件前,浏览器将不会下载./StockChart.js文件和它的依赖。

如果React要渲染<StockChart />组件时,组件依赖的代码还没下载好,会怎样呢? 这就是为什么我们添加了<React.Suspense/>。在代码未下载好前,它将会渲染fallbackprops属性传入的值,当全部子节点依赖的代码都准备好后,才会去渲染子节点内容。

现在App将会被打包成两个文件。

main.js文件只有36kb,包含<StockChart />及其依赖的代码文件89KB。

在优化后, 如下图,浏览器展示了<StockTable />需要消耗的时间。

浏览器用了760ms去下载main.js(以前是1250ms)和执行脚本消耗61ms(以前是487ms). 展示<StockTable />只用了1546ms(以前是2460ms)。

预加载-懒加载组件

现在我们已经让App加载的更快了。但还有另一个问题。

用户在第一次点击Item时,会展示"Loading...."的回退方案的组件。这是因为App需要等待浏览器加载好<StockChart />的代码。

如果我们想避免展示"Loading...."这样的loading状态,我们需要在用户点击之前就加载好代码。

一个简单实现预加载代码的方式就是提前调用React.lazy()

const stockChartPromise = import("./StockChart");const StockChart = React.lazy(() => stockChartPromise);复制代码

当我们调用dynamic imoprt时,组件就会开始加载,并且它不会阻塞<StockTable />组件的加载。

看下App加载的记录以及与未修改版本的对比

当用户在1s内点击Item时,才会看到“Loading...”

你也可以使用你自己的方式去优化lazy函数,让预加载组件更加通用方便。

function lazyWithPreload(factory) {  const Component = React.lazy(factory);  Component.preload = factory;  return Component;}const StockChart = lazyWithPreload(() => import("./StockChart"));// somewhere in your component ...  handleYouMayNeedToRenderStockChartSoonEvent() {    StockChart.preload();  }...复制代码

预渲染组件

以上功能已经满足Demo App的使用了。但对于更大型的项目,在懒加载组件被加载之前,组件可能还会有其他懒加载组件的代码或数据,所以用户还是需要时间等待组件加载。

那另外一种预加载组件的方式就是提前渲染它。在页面中渲染组件,但是并不在页面中展示,也就是隐藏渲染。

class App extends React.Component {  state = {    selectedStock: null  };  render() {    const { stocks } = this.props;    const { selectedStock } = this.state;    return (      
Loading...}>
this.setState({ selectedStock })} /> {selectedStock && (
this.setState({ selectedStock: false })} /> )} {/* Preload
*/}
); }}复制代码

在App第一次渲染后,React将会加载<Stockchart />并尝试去渲染组件,所以组件需要的依赖或代码也会被加载。

我们将懒加载组件包裹在一个隐藏的div中, 在加载之后页面不会展示任何东西。并且还用了React.suspense包裹住这个div,且其fallback值为null,这样它在加载时也不会被展示出来。

注:hidden属性通常表明该节点是不相关的,浏览器将不会渲染具有这个属性的元素。而React并不会对这个属性做任何特殊处理(但在未来的版本中可能会较低优先级处理被隐藏的组件)

还有什么呢?

最后一个方法在很多场景下是可用的,但它仍有一些问题。

第一, 对于被隐藏渲染的懒加载组件, hidden属性并不是完全有效的。举个例子,使用的懒加载组件将不会被隐藏(可以使用portal来实现隐藏功能且不用一个额外的div,但这只是一个hack方式,在未来它将不会被使用)。

第二,虽然Dom节点已经被隐藏,但还是添加了额外的Dom节点,这可能会成为一个性能问题。

一个更好的办法就是,通知react去渲染这个懒加载组件,但在加载后并不把它添加到Dom树中。但据我所了解,在当前版本的React中是无法实现的。

另外我们能做的改进就是重复使用我们预渲染时准备的Dom,这样当真正要去渲染图表组件时,React就无需再创建一遍它。如果用户将会点击某只股票,我们可以在用户点击前用正确的数据渲染它()

这就是文章的全部了,感谢阅读。


《IVWEB 技术周刊》 震撼上线了,关注公众号:IVWEB社区,每周定时推送优质文章。

  • 周刊文章集合:

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

你可能感兴趣的文章
计算机存储数据方式
查看>>
[置顶] Jquery之ShowLoading遮罩组件
查看>>
ACE 格式化输出到console
查看>>
display:none与visibility:hidden的区别。
查看>>
LeetCode-287 寻找重复数
查看>>
架构师不可不知的十大可扩展架构
查看>>
HiveServer2 Impersonation
查看>>
oracle查询当前用户下的所有表、表对应的所有表字段、表的主键字段名称
查看>>
maven的profile和filter插件管理配置项
查看>>
Centos 7源码编译安装MySQL5.5及配置
查看>>
我的友情链接
查看>>
JUnit4中使用Hamcrest测试框架的assertThat断言_小实例
查看>>
Linux Server - APT
查看>>
VMware Workstation 虚拟机问题!
查看>>
我的友情链接
查看>>
JavaScript函数
查看>>
ubuntu16.04 改变网卡名称 Ubuntu server 14.04 LTS 升级 16.04 LTS
查看>>
序列化与反序列化的简便实用封装 续
查看>>
PHP5.1下安装json扩展
查看>>
Skype For Business Server 2015 离线消息
查看>>