React 16.6 提供的一个新的开放一部分功能的 Suspense
代码
import React, { Suspense, lazy } from 'react'

const LazyComp = lazy(() => import('./lazy.js'))

let data = ''
let promise = ''
function requestData() {
if (data) return data
if (promise) throw promise
promise = new Promise(resolve => {
setTimeout(() => {
data = 'Data resolved'
resolve()
}, 2000)
})
throw promise
} function SuspenseComp() {
const data = requestData() return <p>{data}</p>
} export default () => (
<Suspense fallback="loading data">
<SuspenseComp />
<LazyComp />
</Suspense>
)

首先我们看到 export 出去的这个组件,他是一个 function component。然后他使用了 Suspense 。然后给他一个 props ,fallback,fallback 里面就是我们一开始看到的 loading data 。然后里面是两个组件

其中 SuspenseComp 也是一个 function component,调用了一个 requestData 。 渲染的是一个 p 标签,然后值是 {data} 。按照这么来讲的话,Suspense 为什么要提供一个 fallback 。一开始显示 loading data,过一份再显示内容呢。这就跟 requestData 有关系了。 requestData 里面先判断是否有 data 和 promise 。这里如果有 promise ,throw 这个 promise 。注意这里是 throw promise。这个 promise 里面是过 2s ,然后对 data 进行赋值。并且把这个 promise 给 resolve 。然后同样也要 throw promise 。
结合我们看到的 demo 的样子可以猜想,一开始运行程序,显示loading data。 过了 2s 后,有 data 和 promsie 了,重新进行渲染,这个时候就显示出了这个 p 标签。这就是 Suspense 执行的过程。
我们在 Suspense 下面渲染了一个或者多个这种异步的组件,有任何一个抛出了 promise ,在这个 promise resolve 之前,都会显示这个 fallback . 这就是 Suspense 最主要的一个原理的功能,用我们的大白话讲出来,当然他具体的实现是非常复杂的。
react 还支持一个方法 lazy,他可以让我们非常方便的实现一个异步组件加载,配合 webpack 可以很方便的实现这个功能。
lazy.js
import React from 'react'

export default () => <p>Lazy Comp</p>

有了这个组件之后,在 index.js 里面实现异步加载就变得非常的简单

const LazyComp = lazy(() => import('./lazy.js'))

调用 lazy , 传入一个方法,里面 import lazy.js。 Lazy Comp 跟 Data resolved 是一起显示出来的,那么这就是 Suspense 的一个特点,在 Suspense 内部有多个组件,他要等所有组件都 resolve 之后,他才会把 fallback 去掉,然后显示出这里面的内容,有任何一个还处于 pending 状态的,那么他还是会显示 fallback .

接下来看一下这两块的源码,打开 React.js,我们发现 Suspense 还是一个常量,是一个 Symbol,叫 REACT_SUSPENSE_TYPE 。然后 lazy ,lazy 就不是一个 Symbol 了。打开 ReactLazy.js
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/ import type {LazyComponent, Thenable} from 'shared/ReactLazyComponent'; import {REACT_LAZY_TYPE} from 'shared/ReactSymbols'; export function lazy<T, R>(ctor: () => Thenable<T, R>): LazyComponent<T> {
return {
$$typeof: REACT_LAZY_TYPE,
_ctor: ctor,
// React uses these fields to store the result.
_status: -1,
_result: null,
};
}

发现 ReactLazy.js 里面的源码也非常简单,lazy 是一个方法,然后他接收一个方法,并且返回一个 Thenable ,Thenable 什么意思呢?就是 promise 这样的一个对象。具有 .then , 而且这个 .then 是个 function 。他接收这个参数,他返回的是一个 LazyComponent 。返回的一个对象,里面有 $$typeof, 是 REACT_LAZY_TYPE。第一个返回的是 _ctor,这个 _ctor 就等于传进来的参数,这个方法,第三个 _status,这个是用来记录 Thenable 的一个状态的,因为在 react 渲染当中,在渲染到 LazyComponent 的时候,他会去调用这个 ctor 。然后返回一个 Thenable 的对象,一般来说我们认为他是一个 Promise , 这个时候 Promise 是属于 pending 状态的,对应的是 -1 。后面到 resolve 或者 reject 的时候,这个 _status 会变化,_result 是用来记录这个对象 resolve 之后返回的那个属性,lazy 里面最终返回出来的组件会放到

_result 里面,后续渲染 lazy 组件的时候,直接渲染 _result 里面的这个组件就好了

React源码 Suspense 和 ReactLazy的更多相关文章

  1. React躬行记(16)——React源码分析

    React可大致分为三部分:Core.Reconciler和Renderer,在阅读源码之前,首先需要搭建测试环境,为了方便起见,本文直接采用了网友搭建好的环境,React版本是16.8.6,与最新版 ...

  2. React源码剖析系列 - 生命周期的管理艺术

    目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理.本系列文章希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期(C ...

  3. React源码解析:ReactElement

    ReactElement算是React源码中比较简单的部分了,直接看源码: var ReactElement = function(type, key, ref, self, source, owne ...

  4. react 源码之setState

    今天看了react源码,仅以记录. 1:monorepo (react 的代码管理方式) 与multirepo 相对. monorepo是单代码仓库, 是把所有相关项目都集中在一个代码仓库中,每个mo ...

  5. React 源码剖析系列 - 不可思议的 react diff

      简单点的重复利用已有的dom和其他REACT性能快的原理. key的作用和虚拟节点 目前,前端领域中 React 势头正盛,使用者众多却少有能够深入剖析内部实现机制和原理. 本系列文章希望通过剖析 ...

  6. React 源码剖析系列 - 生命周期的管理艺术

    目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理. 本系列文章 希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期 ...

  7. 读react源码准备

    git源码地址:https://github.com/facebook/react react 里面就是 react源码 react里面的react文件夹就是react源码,react源码非常的少,总 ...

  8. react源码之render

    1.最近学习react源码,刚刚入门,看了render的原理,到了fiberRoot的创建 如图:

  9. React源码之组件的实现与首次渲染

    react: v15.0.0 本文讲 组件如何编译 以及 ReactDOM.render 的渲染过程. babel 的编译 babel 将 React JSX 编译成 JavaScript. 在 ba ...

随机推荐

  1. Lab3:虚拟内存管理

    前言 虚拟内存是计算机系统内存管理的一种技术.它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要 ...

  2. Redis NOAUTH Authentication required

    redis设置密码后停止服务报错,NOAUTH Authentication required 可以修改/etc/init.d/redis文件中的stop命令 $CLIEXEC -p $REDISPO ...

  3. 《Linux就该这么学》培训笔记_ch06_存储结构与磁盘划分

    <Linux就该这么学>培训笔记_ch06_存储结构与磁盘划分 文章最后会post上书本的笔记照片. 文章主要内容: Linux系统的文件存储结构(FHS标准) 物理设备命名规则(udev ...

  4. [记录]UserControl 的一个值得注意的问题 [属性" * "的代码生成失败.错误是:"程序集"*.Version=1.0.0.0,Culture=neutral,..........无标记为序列化"

    开发时在做UserControl,需要注意的List<>集合问题~~~! 其他类型的集合可能也存在这样的问题,但是我没去测试,在写集合的时候一般List<>用的多点,所以经常碰 ...

  5. [转帖]AWR报告参数:DB TIME和DB CPU

    AWR报告参数:DB TIME和DB CPU http://blog.itpub.net/12679300/viewspace-1182396/ 一.前言:AWR报告是了解ORACLE运行的一个重要报 ...

  6. Qt 文件选项对话框弹出两次

    1 问题 ​ 在Qt 5.12.0 版本中,用 QFileDialog 类来做文件选择时候,发现当弹出对话框后,选择完文件后,又弹出文件选择对话框. 2 原因查找 2.1 代码 QFileDialog ...

  7. 【SCALA】2、驼峰,下划线互转

    1.刚开始写scala,发现确实还是很不熟悉,api以及语法的使用都不是很简洁,这写出来跟java也没差多少... 献丑了 package spark /** * @ProjectName: cutt ...

  8. sqlserver分布式事务

    启动服务中的Distributed Transaction Coodinator后 创建链接服务器ender-pc\subx 设定连接服务器RPC OUT 以及RPC属性为True 实验一下代码 创建 ...

  9. JQuery的使用案例(二级联动,隔行换色,轮播图,广告插入)

    JQuery的使用案例 (一)利用JQuery完成省市二级联动 第一步:确定事件(change事件),在绑定的函数里面获取用户选择的省份 第二步:创建二维数组来存储省份和城市 第三步:遍历二维数组中的 ...

  10. 引入 ServletContextListener @Autowired null 解决办法

    public class ScheduleController implements ServletContextListener { @Autowired private ScheduleServi ...