本文共 7921 字,大约阅读时间需要 26 分钟。
by Boris Sever
通过鲍里斯·塞弗(Boris Sever)
React 16.6 brought code-splitting to a new level. You can now load your components when it’s really needed without installing additional libraries.
React 16.6将代码拆分提升到一个新的水平。 现在,您可以在真正需要时加载组件,而无需安装其他库。
Webpack defines code-splitting as:
Webpack将代码拆分定义为:
“technique of splitting your code into various bundles which can then be loaded on demand or in parallel”. []
“将您的代码分成各种捆绑包,然后可以按需或并行加载的技术”。 [ ]
Another way to say: “loading on demand or in parallel” is lazy-loading.Opposite of lazy-loading is eager-loading. Here everything is loaded no matter if you use it or not.
另一种说法是:“按需加载或并行加载 ”是延迟加载 。延迟加载的对立面是快速加载 。 无论是否使用,这里都会加载所有内容。
Sometimes we have to introduce a big chunk of code to cover some functionality. This code can be importing 3rd party dependency or writing it on our own. This code then affects the main bundle’s size.
有时我们必须引入一大堆代码来覆盖某些功能。 此代码可以导入第三方依赖关系,也可以自己编写。 然后,此代码会影响主捆绑包的大小。
Downloading a few MBs is a piece of cake for today’s internet speed. We still have to think about the users with a slow internet connection or using mobile data.
对于当今的互联网速度而言,下载几MB只是小菜一碟。 我们仍然必须考虑互联网连接速度慢或使用移动数据的用户。
Probably the most popular library for lazy loading of React components is .
延迟加载React组件最流行的库可能是 .
It’s important that reactjs.org still recommends react-loadable
if your app is rendered on the server. []
重要的是,如果您的应用程序在服务器上呈现,则reactjs.org仍然建议react-loadable
。 [ ]
react-loadable
is actually pretty similar to the new approach by React. I will show this in the following demo.
实际上, react-loadable
与React的新方法非常相似。 我将在以下演示中对此进行展示。
Let's see what reactjs.org has to say about it:
让我们看看reactjs.org对此有何评论:
“If you’re using , , , or a similar tool, you will have a Webpack setup out of the box to bundle your app.
“如果您使用的是 , , 或类似的工具,则将有一个开箱即用的Webpack设置来捆绑您的应用程序。
If you aren’t, you’ll need to setup bundling yourself. For example, see the and guides on the Webpack docs.“
如果不是,则需要设置捆绑自己。 例如,请参阅Webpack文档上的“ 和 ”。”
Ok, so Webpack is required, which handles dynamic imports of the bundles.
好的,因此需要Webpack ,它可以处理捆绑包的动态导入。
The following demo is generated using Create React App.
And in that case, Webpack is already configured and we’re ready to go.
以下演示是使用Create React App.
生成的Create React App.
在这种情况下, Webpack已经配置好了,我们就可以开始了。
For this demo, we will use .
react-pdf
is an awesome library used for creating PDF files on the browser, mobile, and server. We could generate a PDF on the server, but if we would rather do it on the client side, it comes with a cost: bundle size.
对于此演示,我们将使用 。
react-pdf
是一个很棒的库,用于在浏览器,移动设备和服务器上创建PDF文件。 我们可以在服务器上生成PDF,但是如果我们希望在客户端上生成PDF,则需要付出一定的代价:包大小。
I’m using extension for Visual Studio Code to see the sizes of the libraries used.
我正在使用Visual Studio Code的 extension来查看所用库的大小。
Let's say our requirement is to generate a PDF file when a user clicks on the button.
假设我们的要求是当用户单击按钮时生成PDF文件。
Now, this is a simple form with only one use case. Try to imagine a huge web app where this is a fraction of possibilities. Maybe this functionality is not used very often by the users.
现在,这是一种只有一个用例的简单形式。 尝试想象一个巨大的Web应用程序,其中可能性很小。 也许用户很少使用此功能。
Let’s put ourselves into that situation. PDF generation isn’t used very often and it doesn’t make sense to load the whole code for every page request.
让我们进入那种情况。 PDF生成并不经常使用,并且对于每个页面请求都加载整个代码没有意义。
I’ll try to show how we can develop a solution with lazy loading and without it.
我将尝试展示如何开发一个有延迟加载和没有延迟加载的解决方案。
For both cases, we will use one component which imports dependencies from react-pdf
and renders a simple PDF document.
对于这两种情况,我们都将使用一个组件来从react-pdf
导入依赖react-pdf
并呈现一个简单的PDF文档。
Nothing spectacular going on here. We importPDFViewer
, Document
, Page
, Text
, View
from react-pdf
. These are all used in render
method of PDFPreview
component.
这里没有什么壮观的事情。 我们从react-pdf
导入PDFViewer
, Document
, Page
, Text
, View
。 这些全部用于PDFPreview
组件的render
方法中。
PDFPreview
receives only one prop
called title
. As the name implies, it is used as a title in a newly generated PDF file.
PDFPreview
仅接收一个称为title
prop
。 顾名思义,它在新生成的PDF文件中用作标题。
pdfStyles.js looks like this:
pdfStyles.js看起来像这样:
Let’s first see how the parent component without lazy loading could look like:
首先让我们看一下没有延迟加载的父组件的样子:
which renders the following view in the browser:
在浏览器中呈现以下视图:
Let's go through the code together:
让我们一起看一下代码:
On line 2 we import PDFPreview
component.
在第2行,我们导入PDFPreview
组件。
On line 6 we initialize the state with default values. name
is a field used as a title in the PDF file, while field PDFPreview
is a boolean which shows or hides PDFPreview
.
在第6行,我们使用默认值初始化状态。 name
是一个字段,用作PDF文件中的标题,而PDFPreview
字段是显示或隐藏PDFPreview
的布尔值。
Now, let's jump to render
method and check what will be rendered.
现在,让我们跳到render
方法并检查将要渲染的内容。
On line 19 and 25 we render an input and a button. When user types into the input, name
in the state is changed.
在第19和25行,我们渲染一个输入和一个按钮。 当用户键入输入时,状态中的name
会更改。
Then when a user clicks on the “Generate PDF ”, showPDFPreview
is set to true
. The component re-renders and shows thePDFPreview
component.
然后,当用户单击“ Generate PDF”时, showPDFPreview
设置为true
。 该组件将重新渲染并显示PDFPreview
组件。
Even though we use PDFPreview
only on user click, all code related to it is included in the app bundle:
即使我们仅在用户单击时使用PDFPreview
,但与之相关的所有代码都包含在应用程序捆绑包中:
This is a development environment. In production, the sizes would be significantly smaller. Still, we’re not splitting the code optimally.
这是一个开发环境。 在生产中,尺寸将明显较小。 尽管如此,我们仍未以最佳方式拆分代码。
We’ve only made small changes and let's go through them.
我们仅作了一些小改动,让我们进行研究。
Line 2 is replaced with: const LazyPDFDocument = React.lazy(() => import("./PDFPreview"
));
第2行替换为: const LazyPDFDocument = React.lazy(() => import("./PDFPreview"
));
Let's see what the React docs say about React.lazy:
让我们看看React文档对React.lazy的评价:
React.lazy
takes a function that must call a dynamicimport()
. This must return aPromise
which resolves to a module with adefault
export containing a React component.
React.lazy
采用了必须调用动态import()
的函数。 这必须返回一个Promise
,该Promise
解析为一个带有default
导出的模块,该模块包含一个React组件。
React.lazy
takes a function that must call a dynamicimport()
. This must return aPromise
which resolves to a module with adefault
export containing a React component. - reactjs.org
React.lazy
采用了必须调用动态import()
的函数。 这必须返回一个Promise
,该Promise
解析为一个带有default
导出的模块,该模块包含一个React组件。 -reactjs.org
On line 27 we use Suspense
, which must be a parent of a lazy-loaded component. When showPDFPreview
is set to true, LazyPDFDocument
is starting to load.
在第27行,我们使用Suspense
,它必须是延迟加载的组件的父代。 当showPDFPreview
设置为true时, LazyPDFDocument
开始加载。
Until the child component is resolved, Suspense
shows whatever is provided to fallback
prop.
在子组件解析之前, Suspense
显示为fallback
道具提供的所有内容。
The end result looks like this:
最终结果如下所示:
We can see 0.chunk.js weights significantly less than before and 4.chunk.js and 3.chunk.js are loaded on button press.
我们可以看到0.chunk.js的权重明显小于之前,并且在按按钮时加载了4.chunk.js和3.chunk.js 。
Every time we are introducing a new dependency into our project, our responsibility is to evaluate its cost and check how it affects the main bundle.
每次我们在项目中引入新的依赖项时,我们的责任就是评估其成本并检查其如何影响主捆绑包。
Then we have to ask is this functionality going to be used rarely and can we load it on demand without sacrificing the user experience.
然后我们要问的是,该功能将很少使用,是否可以在不牺牲用户体验的情况下按需加载它。
If the answer is yes, then React.Lazy
and Suspense
really help us with that task.
如果答案是肯定的,那么React.Lazy
和Suspense
确实可以帮助我们完成该任务。
Thank you for reading! Please share it with anyone who might find it useful and leave feedback.
感谢您的阅读! 请与可能有用的任何人分享并留下反馈。
翻译自:
转载地址:http://fbkzd.baihongyu.com/