我正在阅读react官方文档,以了解关于react lazy的知识。
根据文档,https://reactjs.org/docs/code-splitting.html#reactlazy
呈现此组件时,它将自动加载包含OtherComponent的捆绑软件。
React.lazy
使用必须调用动态import()
的函数。这必须返回一个Promise
,该解析为包含默认导出的包含React组件的模块。正常导入
import OtherComponent from './OtherComponent'; function MyComponent() { return ( <div> <OtherComponent /> </div> ); }
惰性导入
const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <OtherComponent /> </div> ); }
但是我从文档中对使用惰性导入组件的优势了解得不多。还有为什么承诺会在导入模块/组件时成为现实?
答案 0 :(得分:3)
单页应用程序(SPA)通常可以通过下载包含您应用所需的所有脚本的捆绑包来工作。浏览器地址栏中的路由和URL更改是通过HTML5 history API处理的。由于浏览器无需刷新来加载应用程序的任何部分,因此可创建强大的用户体验-您可以立即从一个页面/ URL导航到另一个页面/ URL。
虽然从理论上讲听起来不错,但实际上,情况却很丑陋。最大的问题之一是捆绑包的大小-在中等复杂度的SPA中,捆绑包的大小很容易达到兆字节。现在,如此大的文件不仅需要花费很长时间下载,而且也不会被浏览器缓存-因此需要一次又一次地获取它们,这反过来会使您的应用程序显得呆滞。
已经进行了许多尝试来解决此问题-asynchronous and deferred loading of scripts,并且进行了代码拆分。代码拆分是指将大型捆绑包拆分为较小的块的技术-这种思想是您尽快下载应用程序的核心或关键部分,然后按需加载其余代码。这解决了上面提到的问题,但是实现代码拆分非常困难。
原因之一是,Webpack之类的工具很难通过较少的人工干预来弄清楚如何有效地拆分代码。在AMD的世界中,define
/require
帮助您定义了代码分割点-因此,您可以先加载关键部分,然后按需求以异步方式加载其余部分。
在React世界中,lazy
让您以较少的人工干预有效地做到这一点。通过定义lazy
,可以表明这部分代码是非关键的,可以根据需要在后台加载。
() => import('./OtherComponent')
的语法也称为dynamic import,它与静态导入import OtherComponent from './OtherComponent'
不同。动态导入是异步的,因此它们始终返回Promise。 承诺确保 依赖 的代码与此延迟加载的模块 执行 仅在脚本加载后。
请考虑以下代码段:
const PurchaseHistory = lazy(() => import('./components/PurchaseHistory'))
class App extends Component {
state = {
purchases: [ ],
};
componentDidMount() {
fetch(`some/api/that/returns/data`)
.then(res => res.json())
.then(res => {
this.setState({ purchases: res.data });
});
}
render() {
return (
<div className="app">
<Suspense fallback={Loader}>
<PurchaseHistory {...purchases} />
</Suspense>
</div>
);
}
}
在上面的代码中,React可以立即使用Loader
渲染应用程序,直到获取成功为止,它甚至不需要加载惰性PurchaseHistory
组件。这样可以节省下载时间,减少内存占用并节省下载和处理PurchaseHistory
组件所需的CPU周期。
Suspense是React 16.6中的新API。
上面的代码与即将推出的另一个名为 Concurrent Rendering 的功能结合在一起,可确保React相当快地渲染应用程序(比React 16更快)。之所以可以这样做,是因为React知道哪些部分至关重要,哪些不重要。
为进一步阅读,我建议这个blog post讨论所有3个功能以及代码示例。
答案 1 :(得分:2)
它使您可以延迟加载其他组件的脚本。如果该脚本与其他脚本分开(例如,不属于您的主捆绑包),那么这将非常有用。
优点是:
当然有缺点:
与往常一样,权衡将对某些项目采取一种方式,而对其他项目则采取另一种方式。大型的单页面应用程序具有用户可能会或可能不会访问的许多部分,这可能会有所帮助;一个很小的页面,其中所有组件可能都在很早就呈现了。
答案 2 :(得分:1)
单页应用程序开始变大时。一次加载所有javascript没有意义。假设您在首页上,并且为“个人资料”部分加载javascript毫无意义,这会减慢首页的页面加载速度。因此,将大型应用程序代码拆分为较大的块将使应用程序性能更好。简而言之lazy loading
您的组件。
答案 3 :(得分:1)
基本上,对于常规导入,它将导入父组件所需的所有子组件。但是,对于延迟加载的子组件,它将异步加载它们。当子组件本身包含许多其他子组件层次结构时,这确实有助于节省父组件的初始加载时间,并最终延长了加载主页面的时间。但是,当对组件使用Lazyloading时,要延迟加载的组件必须使用带有回退属性的“ Suspense”标签封闭,因为当父组件加载并且提供了jsx时,延迟加载的组件的内容将不可用然后将加载fallback属性中的
。答案 4 :(得分:1)
简单地说,如果不使用延迟加载的任何组件,则不会在浏览器中下载它。
在下面的代码中,导入了Hello
和Bye
。
但是,由于仅使用Hello
,因此不包含Bye
的代码。
import React, { lazy, Suspense } from "react";
import ReactDOM from "react-dom";
const Hello = lazy(() => import("./components/Hello"));
const Bye = lazy(() => import("./components/Hello"));
function App() {
return (
<Suspense fallback={<>Loading...</>}>
<Hello />
</Suspense>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
您可以继续关注CodeSandbox
在Netlify上检查deployed site时,
您可以从站点上看到Bye
尚未加载。
您可以通过按需加载组件来利用此优势。
无耻的插件:如果您想进一步了解其他用例,请查看我的博客条目Loading React Components Dynamically on Demand using React.lazy。