首页 文章

React的懒惰是什么?

提问于
浏览
2

我正在通过官方文档来了解反应懒惰 .

根据文档,https://reactjs.org/docs/code-splitting.html#reactlazy

这将在渲染此组件时自动加载包含OtherComponent的包 . React.lazy采用必须调用动态import()的函数 . 这必须返回一个Promise,它解析为一个带有包含React组件的默认导出的模块 . 正常导入从'./OtherComponent'导入OtherComponent;
function MyComponent(){
回来(

<DIV> <OtherComponent /> </ DIV> ); } 延迟导入const OtherComponent = React.lazy(()=> import('./ OtherComponent')); function MyComponent(){ 回来( <DIV> <OtherComponent /> </ DIV> ); }

但是我从文档中无法理解使用lazy导入组件的优势 . 另外为什么要承诺导入模块/组件?

5 回答

  • 2

    基本上,对于正常导入,它会导入父组件所需的所有子组件 . 但是,对于Lazy加载的子组件,它会异步加载它们 . 当子组件本身包含许多其他子组件层次结构并最终延长加载主页面的时间时,这确实有助于保存父组件的初始加载时间 . 但是,当对组件使用Lazyloading时,要延迟加载的组件必须用带有fallback属性的“Suspense”标记括起来,因为当父组件加载并提供jsx时,延迟加载的组件的内容将不可用然后将加载fallback属性 .

  • 2

    单页应用程序(SPA)通常通过下载包含应用程序所需的所有脚本的 bundle 来工作 . 浏览器地址栏中的路由和URL更改通过HTML5 history API处理 . 这创建了一个非常强大的用户体验,因为浏览器永远不需要 refresh 来加载应用程序的任何部分 - 您可以立即从一个页面/ URL导航到另一个页面/ URL .

    虽然这在理论上听起来不错,但在实践中,事情是丑陋的 . 最大的问题之一是捆绑包大小 - 在中等复杂度的SPA中,捆绑包大小可以轻松达到兆字节 . 现在,这样的大文件不仅需要很长时间才能下载,而且还没有被浏览器缓存 - 所以它们需要一次又一次地获取,这反过来会使你的应用看起来很迟钝 .

    已经有很多尝试来解决这个问题 - asynchronous and deferred loading of scripts和代码拆分 . 代码拆分是指将您的超级捆绑包拆分为更小的技术 chunks - 这个想法是您尽快下载应用程序的核心或关键部分,然后根据需要加载其余代码 . 这解决了上面提到的问题,但是实现代码分割变得非常困难 .

    其中一个原因是,像Webpack这样的工具很难找到如何有效地分割代码,而不需要人工干预 . 在AMD世界中,define/require帮助您定义代码分割点 - 因此您可以先加载关键部分,然后以异步方式按需加载休息 .

    在React世界中, lazy 允许您通过较少的人工干预有效地完成 . 通过定义 lazy ,您可以指示代码的这一部分是非关键的,可以根据需要在幕后加载 .

    () => import('./OtherComponent') 语法也称为dynamic import,它与静态导入不同: import OtherComponent from './OtherComponent' . 动态导入是异步的,因此它们总是返回Promise . 一个 Promise 确保在这个延迟加载的模块上 depends 的代码,仅在脚本加载后 executes .

    请考虑以下代码段:

    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

    它允许您延迟加载其他组件的脚本 . 如果该脚本与其他脚本分开(例如,不是主要包的一部分),这将主要有用 .

    优点是:

    • 您的初始启动速度更快(假设您的组件不是初始显示的一部分)

    • 如果用户从不做任何显示组件的事情,则另一个组件's script never needs to be loaded (so that' s保存了一个HTTP请求和该模块消耗的内存加载量)

    当然,也有缺点:

    • 当需要显示组件时,它会因需求加载其他组件的脚本而延迟(HTTP请求,顶级模块)评价)

    • 复杂性如果你正在捆绑,现在你必须在捆绑包中有一些脚本,而其他脚本不在捆绑包中

    与往常一样,对于某些项目,权衡将采用单向方式,对于其他项目则采用另一种方式 . 一个大型的单页应用程序可能会有用户可能会访问或不访问很多部分 . 可能不会在早期渲染所有组件的小页面 .

  • 1

    简单地说,如果没有使用懒惰加载的任何组件,则不会在浏览器中下载 .

    在下面的代码中,导入 HelloBye . 但由于仅使用 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

    Edit so.answer.53174915

    当您检查Netlify上的deployed site时,
    你可以从网站上看到没有加载 Bye .

    enter image description here


    您可以通过按需加载组件来利用此功能 .

    Shameless plug :如果您想了解更多有关其他用例的信息,请查看我的博客文章Loading React Components Dynamically on Demand using React.lazy .

  • 1

    当您的单页应用程序开始大量增长时 . 一次加载所有的javascript是没有意义的 . 让's say you are on Homepage and loading javascript for Profile section wouldn' t有意义,它会减慢主页的页面加载速度 . 因此,将大型应用程序代码拆分为相当大的块将使应用程序的性能更好 . 总之 lazy loading 你的组件 .

相关问题