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. git手册查询

    1.创建版本库 通过git init命令把此目录变成Git可以管理的仓库; 添加文件到Git仓库,分两步 第一步:git add <file>,注意,可反复多次使用,添加多个文件:例如 g ...

  2. 阿里云 azkaban 发邮件的坑

    azkaban : 是一个 任务调度平台 安装文档: https://azkaban.readthedocs.io/en/latest/getStarted.html 因为阿里云是禁止掉是STMP 2 ...

  3. STL源码剖析 阅读笔记

    结构图:

  4. centos中更新glibc库文件到2.17

    1 确保安装过gcc yum install gcc 2 获取glibc相关版本 wget http://ftp.gnu.org/pub/gnu/glibc/glibc-2.17.tar.xz 3 解 ...

  5. Effective.Java第1-11条

    1. 考虑使用静态工厂方法替代构造方法 一个类可以提供一个公共静态工厂方法,它只是返回类实例的静态方法.例如JDK的Boolean的valueOf方法: public final class Bool ...

  6. vs2019发布Web到云服务器(IIS)

    捣鼓了也有几天,到处收集资料终于折腾出来,做点小笔记 原文地址:https://www.cnblogs.com/potential/p/3751426.html 一.我的环境: Windows Ser ...

  7. TestNG系列(五)TestNG测试报告

    以TestNG执行测试方法后会生成test-output测试结果集,其中index.html是测试结果的展示.TestNG的测试报告可以通过IReporter监听自定义,也可以通过第三方工具(Repo ...

  8. spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码

    1.背景 在实际开发中,我可能会对请求接口做统一日志输出,或者统一参数解析,验签,统一响应加密等,通常会用到aop,实际案例如下 2.代码 package com.qianxingniwo.log; ...

  9. C#条码生成及打印实例代码

    ";//条码 ; ; //打印按钮 private void button1_Click(object sender, EventArgs e) { //实例化打印对象 PrintDocum ...

  10. Google Chrome 浏览器JS无法更新解决办法

    JS无法更新原因: 浏览器为了加载快,默认是按照自定规则更新缓存,非实时更新. 我们在开发的时候,JS变动很快,需要即时让浏览器加载最新文件,也就是禁用浏览器缓存 (1)使用F12进入开发者模式,找到 ...