React中Suspense及lazy()懒加载及代码分割原理和使用方式

目录
  • React.lazy()
    • 概括
    • 为什么需要懒加载
    • 如何进行代码分割
  • Suspense
    • Suspense应用场景
    • Suspense实现原理
  • 总结

Suspense和lazy()都是react中比较新的特性,在项目中使用还比较少,但是学习一下有助于在后面的项目中使用,同样可以一窥React未来的发展方向

React.lazy()

概括

顾名思义lazy()方法是用来对项目代码进行分割,懒加载用的.只有当组件被加载,内部的资源才会导入

为什么需要懒加载

在React的项目中import导入其他组件和库都是默认在初始直接导入的,webpack等打包工具会将import导入的文件直接合并到一个大文件中,如果项目很大,打包完后初始化加载时需要加载的文件会很大,这时候就需要代码分割

官方文档中的例子

项目中:

// app.js
import { add } from './math.js';
console.log(add(16, 26)); // 42
// math.js
export function add(a, b) {
  return a + b;
}

打包后

function add(a, b) {
  return a + b;
}
console.log(add(16, 26)); // 42

如何进行代码分割

在你的应用中引入代码分割的最佳方式是通过动态 import() 语法,这是官方文档中说的

动态import例子:

静态导入:

import { add } from './math';
console.log(add(16, 26));

动态导入:

import("./math").then(math => {
  console.log(math.add(16, 26));
});

使用了动态导入之后,webpack检测到这种语法会自动代码分割,也就是压缩到两个文件里

React.lazy()就是对这个种动态导入方式的优化方法

使用:

const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
  return (
    // Displays <Spinner> until OtherComponent loads
    <React.Suspense fallback={<Spinner />}>
      <div>
        <OtherComponent />
      </div>
    </React.Suspense>
  );
}

发现没有原来的动态导入写法像 Promise的写法链式调用,现在动态导入的方式,有点类似于Async写出来是同步使用的,可以直接讲返回的Promise对象作为组件使用,当这个组件pending是显示的是Suspense中fallback的内容,只有resolve才显示加载好的组件.

所以可以看出Suspense和React.lazy()需要结合在一起用,否则会报错缺少Placeholder UI`

Suspense

Suspense的英文意思是悬念,悬停**,Suspense的作用就是在遇到异步请求或者异步导入组件的时候等待请求和导入完成再进行渲染,**相比普通的组件, 我们是要求render是一个纯函数,一旦开始渲染不会等待,而有了Suspense后我们可以再render过程中写一部代码.

Suspense应用场景

Subspense存在两种应用场景,第一种就是动态导入组件(如上),一种就是异步请求数据(暂时不支持,大概16.9版本)

动态导入组件

动态导入组件上面的例子就是上面的代码片段,就是当这个组件pending是显示的是Suspense中fallback的内容,只有resolve才显示加载好的组件,所以fallback不能为空

优点

好处在于我们可以不用创建一些组件状态的变量来控制是否显示loading画面和真正组件,这部分逻辑直接由Suspense内部实现. 而且还有一种场景就是当一个父组件中,有多个动态加载的组件,Suspense可以直接将loading状态聚合,只有当所有组件加载完成才显示,这里免去了复杂的逻辑判断.

数据请求后渲染页面

Suspense暂时还不支持数据请求后渲染, 预计是在16.9版本也就是2019年年中发布,但是以及有了实例使用的方法,下面这里就是官方的示例代码,这里做一些翻译解释

// unstable_createResource这个就是一个封装的请求数据的插件,不用太清楚类似于fetch
import {unstable_createResource} from 'react-cache';
// 声明请求数据的方法
const TodoResource = unstable_createResource(fetchTodo);
//内部请求TodoResource.read(props.id) 就是异步请求数据
function Todo(props) {
  // Suspends until the data is in the cache
  const todo = TodoResource.read(props.id);
  return <li>{todo.title}</li>;
}
function App() {
  return (
    // 只有当两个Todo内部的异步请求都完成后才能渲染出来,否则渲染<Spinner/>
    <React.Suspense fallback={<Spinner />}>
      <ul>
        {/* Siblings fetch in parallel */}
        <Todo id="1" />
        <Todo id="2" />
      </ul>
    </React.Suspense>
  );
}

这就是Suspense请求数据时的使用的方法,同样解决了loading状态的问题,相当于再render过程中加入了异步副作用操作,再普通的组件中异步操作是不起作用的,因为先渲染完,异步数据才会返回,这时候已经渲染完了.

Suspense实现原理

Subspense的实现主要就是利用了**ComponentDidCatch这个生命周期,这个什么周期就是用来捕获子组件树中的任何Javascript异常**

源码就不分析了,这里说一下大概的流程步骤:

  • 父组件渲染到子组件时发现异步请求,直接抛出错误,捕获的结果是一个Promise对象
  • ComponentDidCatch捕获这个Promise对象,pending状态下渲染fallback的
  • 当resolve时重新render,遇到下一个异步请求重复上面操作
  • 直到整个父组件的抛出的promise对象都为resolve,将loading替换为真正的组件.

总结

Suspense其实就是将原来放在外面处理的异步请求也就是副作用放到渲染过程中进行操作,这样render这个函数就不再是纯函数了,但是非常直观方便,不需要再用很多状态来控制loading显示,而异步请求的结果无法预测会导致很多bug.

等到Suspense支持数据请求的场景时,我会考虑把它运用到自己的项目中, 感觉确实方便很多本来就觉得Loading状态有点多余,虽然现在用的是Dva,会自动给effect创建loading状态的,还不是特别需要.

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • React18 中的 Suspense API使用实例详解

    目录 什么是新的 ReactJS Suspense API,什么时候应该使用它? 什么是Suspense API? 什么是 transition API? 最后 什么是新的 ReactJS Suspense API,什么时候应该使用它? 何时使用:当组件开始变大并且您在同一页面上有许多组件时,您可能希望开始优化下载到客户端浏览器的方式和时间. 为此,React 为您提供了lazyAPI,它允许您将组件标记为lazy,这意味着被lazy包裹的组件,将会在第一次真正使用时被加载,而不是页面初始化的时

  • react  Suspense工作原理解析

    目录 Suspense 基本应用 Suspense 原理 基本流程 源码解读 - primary 组件 源码解读 - 异常捕获 源码解读 - 添加 promise 回调 源码解读-Suspense 首次渲染 primary 组件加载完成前的渲染 primary 组件加载完成时的渲染 利用 Suspense 自己实现数据加载 Suspense 基本应用 Suspense 目前在 react 中一般配合 lazy 使用,当有一些组件需要动态加载(例如各种插件)时可以利用 lazy 方法来完成.其中

  • React Suspense前后端IO异步操作处理

    目录 简单介绍Suspense Suspense主要用法和场景 一. React18之前的做法 二. React18之后 Suspense配合前端表格组件处理前后端IO异步操作 简单介绍Suspense Suspense主要用来解决网络IO问题,它早在2018年的React 16.6.0版本中就已发布.它的相关用法有些已经比较成熟,有的相对不太稳定,甚至经历了重命名.删除: 在render函数中,我们可以写入一个异步请求,请求数据 react会从我们缓存中读取这个缓存 如果有缓存了,直接进行正常

  • react中Suspense的使用详解

    关于Suspense的使用,先来看下示例代码 const OtherComponent = React.lazy(() => import('./OtherComponent')); function MyComponent() { return ( <div> <Suspense fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> </div&

  • React中Suspense及lazy()懒加载及代码分割原理和使用方式

    目录 React.lazy() 概括 为什么需要懒加载 如何进行代码分割 Suspense Suspense应用场景 Suspense实现原理 总结 Suspense和lazy()都是react中比较新的特性,在项目中使用还比较少,但是学习一下有助于在后面的项目中使用,同样可以一窥React未来的发展方向 React.lazy() 概括 顾名思义lazy()方法是用来对项目代码进行分割,懒加载用的.只有当组件被加载,内部的资源才会导入 为什么需要懒加载 在React的项目中import导入其他组

  • hibernate 中 fetch=FetchType.LAZY 懒加载失败处理方法

    对这种懒加载问题,最后的做法是利用Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,使得Hibernate的Session的生命周期变长,直到这个请求结束,具体是通过一个Filter来实现的. 那么,如果现在我们想用Hibernate懒加载特性,又想用延长session的生命周期,知道将数据提到页面显示(经过action层),那么我们就得在web.xml文件中增加以下配置: <!-- 配置

  • androidx下的fragment的lazy懒加载问题详解

    网上关于androidx的fragment懒加载文章已经有很多,各有侧重.几乎都点到了sexMaxLifecycle和修改FragmentPagerAdapter.很少看到经过实践的文章,谨以此文,更加详尽的把实践后的结果记录下来,赠予有缘人. 一.前置准备工作 几个关于androidx的fragment懒加载方案,都离不开如下几个包: androidx.fragment:fragment:1.1.0-alpha07 以上,支持setMaxLifecycle方法即可 androidx.viewp

  • 在springboot中实现个别bean懒加载的操作

    懒加载---就是我们在spring容器启动的是先不把所有的bean都加载到spring的容器中去,而是在当需要用的时候,才把这个对象实例化到容器中. @Lazy 在需要懒加载的bean上加上@Lazy就可以了 补充知识:springboot组件懒加载的坑及加载规则 什么是懒加载? 懒加载的意思是不在项目启动的时候实例出来这个组件 @RestController public class ApiController { @Autowired Skill kobSkillImpl; @Request

  • Android界面数据懒加载实现代码

    大家在使用手机新闻客户端的时候就会有一个发现,大多数的新闻客户端都会把新闻分类,诸如头条.娱乐.体育.科技等等,如何实现这种界面的呢?这个实现起来其实很简单,就是在一个Fragment中实现多个ViewPage的切换,再在ViewPage的上面放一个TabLayout,关联起来就可以实现联动效果.如果大家感觉不太明了的话,以后我可以专门写一篇关于Fragment中放入多个ViewPage的博客,今天,我主要介绍的是怎样实现界面即Fragment的懒加载.那么,大家就会奇怪了既然是加载界面直接加载

  • Android优化方案之Fragment的懒加载实现代码

    一.背景 在Android应用中,ViewPager是我们不可避免使用的一个控件,因为它可以使我们在占用较少空间的同时,增强内容的丰富性,同时以其内部流淌着Google的血液,所以它几乎成了每一个App的标配控件.但是,假如ViewPager的每一个Fragment都需要通过网络拉取数据加载,而ViewPager是默认加载前两项的,所以在很容易造成网络丢包或者网络堵塞等问题,所以Fragment使用懒加载是非常有必要的. 举个栗子: 如上图所示,我们有两个大的Tab:人物和风景.而人物Tab下有

  • 详解Android 在 ViewPager 中使用 Fragment 的懒加载

    我们先看一下效果: 首先,我们要知道什么是懒加载: 懒加载,就是先初始化控件,在用户可见的时候再加载数据. 为什么要懒加载? 懒加载多被使用在新闻资讯类客户端中,试想那么多的分类如果一下子都加载出来,真的是极大地消耗了系统资源.可能有人会说 ViewPager 有 viewPager.setOffscreenPageLimit() 的方法,我们传个 0 进去不就好了吗?看过源码的应该知道,即便你传了 0 进去,系统也会默认为 1 的,也就是 ViewPager 依然会加载当前页面的前后各一个 F

  • angular实现图片懒加载实例代码

    这两天一直纠结angular的图片懒加载插件中无法自拔.在使用过程深深感到js学艺不精的痛苦,想修改源码又不会修改,只能尽力压榨如何使用插件上.这里主要谈谈在使用插件的过程遇到的一些问题. 一)我使用的是angular-imglazyload这个插件.[https://www.npmjs.com/package/angular-imglazyload]主要是这个插件小不依赖jquery库,然后下载源码运行成功后,我就整合到自己项目上运行,结果发现竟然只有前2张加载了,滚动了都没有反映.下面是我的

  • react中路由和按需加载的问题

    目录 react路由和按需加载问题 1 基本的路由设置 2 如何完成路由的菜单部分 3 如何将每个路由的js文件分开输出 4 react-router按需加载配置 5 最后效果 react路由的基本使用 1.先下包 2.导入并使用 3.使用HashRouter包裹整个应用 4.使用Link指定导航链接 5.使用Route指定路由规则(哪个路径展示哪个组件) 6.精确匹配 :exact 7.Switch 8.处理404页 Redirect react路由和按需加载问题 1 基本的路由设置 reac

  • Hibernate懒加载之<class>标签上的lazy

    本文研究的主要是 lazy的概念:在真正使用某个对象的时候才去加载该对象. Hibernate的lazy策略可以使用在: 1.<class>标签上,可以取值:true/false. 2.<property>标签上,可以取值:true/false,需要类增强工具,对字节码进行修改(这个没多大意义). 3.<set>和<list>标签上,可以取值:true/false/extra. 4.<many-to-one>和<one-to-one>

随机推荐