在React 16.6中延迟加载(和预加载)组件
React 16.6增加了一个新功能,使代码拆分更加容易: React.lazy()
。
让我们看看如何以及为什么在一个小型演示中使用此功能。
我们有一个显示股票清单的应用程序。 当您单击一只股票时,它将显示一个图表:
这就是全部。 您可以在github存储库中阅读完整的代码(也可以检查pull请求,以查看差异和应用程序正在运行的每个版本的运行版本)。
对于本文,我们仅关心App.js
文件中的内容:
我们有一个App
组件,该组件接收股票列表并显示<StockTable/>
。 从表中选择股票后, App
组件将显示该股票的<StockChart/>
。
有什么问题? 好吧,我们希望我们的应用程序能够快速发展并尽可能快地显示<StockTable/>
,但是我们正在等待它下载直到浏览器下载(并解压缩,解析,编译和运行) <StockChart/>
的代码。
让我们看一下显示<StockTable/>
需要多长时间:
显示StockTable(具有模拟的Fast 3G网络和4x减速CPU)需要2470 ms。
我们要运送到浏览器的那些(压缩)125KB中有什么?
不出所料,我们有反应,反应主导和一些反应依赖性。 但是我们也有时刻,lodash和胜利,我们只需要<StockChart/>
,而不需要<StockTable/>
。
为了避免<StockChart/>
依赖项减慢<StockTable/>
的加载速度,我们该怎么做? 我们延迟加载组件。
延迟加载组件
使用动态导入,我们可以将捆绑的javascript分成两部分,一个是仅包含显示<StockTable/>
所需代码的主文件,另一个是包含代码和<StockChart/>
所需的依赖项的文件。
这项技术是如此有用,以至于React 16.6添加了一个API,以使其更易于与React组件一起使用: React.lazy()
。
为了使用React.lazy()
在我们的App.js
我们做出两个改变:
首先,我们将静态导入替换为对React.lazy()
的调用, React.lazy()
其传递返回动态导入的函数。 现在,在我们第一次渲染它之前,浏览器将不会下载./StockChart.js
(及其依赖项)。
但是,当React想要渲染<StockChart/>
而又没有代码时会发生什么呢? 这就是我们添加<React.Suspense/>
。 它将加载fallback
道具而不是其子代,直到加载所有子代的所有代码为止。
现在,我们的应用程序将捆绑在两个文件中:
js主文件为36KB。 另一个文件为89KB,具有./StockChart
的代码及其所有依赖项。
让我们再次看到多少花费在浏览器中显示<StockTable/>
这些变化:
浏览器需要760毫秒(而不是1250毫秒)来下载主要js文件,而花费61毫秒(而不是487毫秒)来评估脚本。 <StockTable/>
在1546毫秒(而不是2470毫秒)中显示。
预加载惰性组件
我们使我们的应用程序加载速度更快。 但是现在我们还有另一个问题:
用户首次单击某个项目时,将显示“正在加载...”后备广告。 那是因为我们需要等到浏览器加载<StockChart/>
的代码。
如果要摆脱“正在加载...”后备广告,我们将必须在用户单击股票之前先加载代码。
预加载代码的一种简单方法是在调用React.lazy()
之前启动动态导入:
当我们调用动态导入时,组件将开始加载,而不会阻止<StockTable/>
的呈现。
看一下跟踪如何从原始的eager-loading应用程序更改:
现在,如果用户在显示表格后不到1秒的时间内单击库存,则只会看到“正在加载...”后备广告。 试试吧 。
您还可以增强lazy
功能,以便在需要时更容易地预加载组件:
预渲染组件
对于我们的小型演示应用程序,这就是我们所需要的。 对于较大的应用程序,惰性组件可能需要先加载其他惰性代码或数据,然后才能呈现。 因此,用户仍然必须等待这些。
预加载组件的另一种方法是在需要它之前实际对其进行渲染。 我们想要渲染它,但是我们不想展示它,所以我们将其渲染为隐藏的:
在第一次渲染应用程序时,React将开始加载<StockChart/>
,但这一次它实际上将尝试呈现<StockChart/>
因此,如果需要加载任何其他依赖项(代码或数据),它将被加载。
我们将惰性组件包装在一个hidden
div
因此在加载后它不会显示任何内容。 然后,将该div
包裹在另一个<React.Suspense/>
,其回退为null
因此在加载时它不会显示任何内容。
注意: hidden
是HTML属性,用于指示该元素尚不相关。 浏览器不会渲染具有此属性的元素。 React对那个属性没有做任何特别的事情(但是它可能会在以后的版本中开始给隐藏的元素一个较低的优先级)。
少了什么东西?
后一种方法在许多情况下很有用,但存在一些问题。
首先,用于隐藏渲染的惰性组件的hidden
属性不是防弹的。 例如,惰性组件可以使用不会被隐藏的门户 ( 有一种hack不需要额外的div,也可以与portal一起使用,但这是一种hack,它会崩溃)。
其次,即使隐藏了组件,我们仍将未使用的节点添加到DOM中,这可能会成为性能问题。
更好的办法是告诉反应以呈现惰性组件,但在加载后不将其提交到DOM。 但是,据我所知,当前版本的React无法实现。
我们可以做的另一个改进是在预加载图表组件时重用我们渲染的元素,因此当我们想要实际显示图表时,React不需要再次创建它们。 如果我们知道用户将点击什么库存,我们甚至可以在用户点击它之前用正确的数据渲染它( 像这样 )。
就这样。 谢谢阅读。
有关更多类似内容,请 在Twitter上 关注 @pomber 。
From: https://hackernoon.com/lazy-loading-and-preloading-components-in-react-16-6-804de091c82d