GMTC全球大前端技术大会(北京站)门票9折特惠截至本周五,点击立减¥480 了解详情
写点什么

React 的未来:与 Suspense 共舞

2019 年 6 月 16 日

React的未来:与Suspense共舞

React 的 16.x 版本自从发布以后就风靡了整个业界。这个版本的新增功能中,最受欢迎的有 Hooks、懒加载、Suspense 和缓存 API 等。


不要以为本文又要教你怎么写 Hooks,我要写的是对 React 未来的展望!如果你从未听过 Hooks 或者 React 中的其他新 API,这篇文章会让你了解这些激动人心的未来。


接下来我们将介绍两个新概念,相关功能预计将在 2019 年第二季度发布:


  • 如何使用 Suspense 获取数据

  • 如何使用 react-cache


虽然我迫不及待想要介绍这些功能,但之前我们还是先来铺垫一下。


React Hooks

React 16.8 正式在稳定版中引入了 Hooks。它在高层级上解决了一些问题:


  • 它引入了使用函数编写所有内容的理念,使代码更加模块化、更易于维护。

  • 它不鼓励使用 HOC 等难以理解的复杂函数。

  • 它不再使用复杂的生命周期,如 componentDidMount、componentDidUpdate 等,免去了编写重复代码的麻烦。


想了解更多内容请点击此处:https://reactjs.org/docs/hooks-intro.html#motivation


下面来看一个 React Hooks 的示例,看看使用它的典型应用长什么样!示例地址:https://codesandbox.io/embed/3rm5jk86wm?fontsize=14


React.lazy

这个名字起得真是恰如其分!当我们想懒加载组件时就可以用上它了:


const TodoList = React.lazy(() => import("./containers/todoList"));
复制代码


在 webpack 中使用动态导入时就能用它做优化了。它能用来创建 bundle,从而提高页面加载速度。下面是一个例子,只要在上面的 Codesandbox 演示中把导入改为以下内容即可:


const TodoList = React.lazy(() => import("./containers/todoList"));const CompletedList = React.lazy(() => import("./containers/completedList"));const AddNewTask = React.lazy(() => import("./containers/addNewTask"));
复制代码


如下图所示,创建了许多独立的 bundle:



Suspense

Suspense 很好用,下面的代码就是很好的例子:


// https://codesandbox.io/s/new-6m2gjimport React, { useState, useEffect, Suspense } from "react";import ReactDOM from "react-dom";import todoListData from "./containers/todoList/todolistData";import Header from "./containers/header";import Clock from "./components/Clock";import "./styles.css";
const TodoList = React.lazy(() => import("./containers/todoList"));const CompletedList = React.lazy(() => import("./containers/completedList"));const AddNewTask = React.lazy(() => import("./containers/addNewTask"));
function App() { const { todolist } = todoListData; const [todoListPayload, setTodoListPayload] = useState(todolist); const [completedTodoList, setCompletedTodoList] = useState([]);
const addTodoTaskHandler = value => { // addTodoTaskHandler };
const removeTodoTaskHandler = ({ id }) => { // Remove from the set of todo list };
const completeTodoTaskHandler = ({ id }) => { // Get item to remove };
return ( <div className="App"> <Header title={"My Tasks"} /> <Clock /> <div className="PageLayout"> <Suspense fallback={<div>Loading...</div>}> <TodoList payload={todoListPayload} completeTodoTaskHandler={completeTodoTaskHandler} /> <CompletedList list={completedTodoList} /> <AddNewTask addTodoTaskHandler={addTodoTaskHandler} /> </Suspense> </div> </div> );}
const rootElement = document.getElementById("root");ReactDOM.render(<App />, rootElement);
复制代码


演示链接:https://codesandbox.io/s/new-6m2gj


仔细检查示例中的代码,我们会看到:


<Suspense fallback={<div>Loading...</div>}>  <TodoList     payload={todoListPayload}     completeTodoTaskHandler={completeTodoTaskHandler}   />  <CompletedList list={completedTodoList} />  <AddNewTask addTodoTaskHandler={addTodoTaskHandler} /></Suspense>
复制代码


只要用 Suspense 包装组件就行了,就是这么简单。我们使用 React.lazy()懒加载了一些组件——TodoList、CompletedList、AddNewTask。由于它会在内部为每个组件生成 bundle,因此网络条件不佳的情况下可能需要花些时间来加载它们。


Suspense 会自动处理加载延迟,显示像 Loading…之类的组件作为 fallback。


未来展望

铺垫结束!下面我们来看看 Suspense 还有什么好玩的内容。


Suspense 和 react-cache

其实 Suspense 在某个 API 被调用时也可以处理我们的加载状态。不过我们先要好好了解一下这个 API。


经过一番搜索,我找到了Shawn Swyx Wang的GitHub库,这里直接引用他文档中的一段话:


React Suspense 是组件从缓存中加载数据时暂停呈现的一种通行方法。

它解决的问题:渲染是和 I/O 绑定时的情况。


“从缓存中加载数据”是一个要点,但怎样真正控制这个 API 呢。


Kent C. Dodds 在他的Egghead课程中讲授了一个重要的概念:如果我们抛出一个 promise,Suspense 会自动得知调用了一个 API 请求。


import React, { Suspense } from "react";
fetchArticles() { // Some fetch API fetching articles}
let isRequestCalled = false;function Content() { let result = []; if (!cache) { const promise = fetchArticles(); isRequestCalled = true; throw promise; // Let suspense know } return <div>Article</div>;}
复制代码


当然,这种方法不是最佳选择,它还是有点不正规。所以我们改用 react-cache 来优化一下:


import React, { Suspense } from "react";
import { unstable_createResource as createResource } from "react-cache";
function fetchArticles() { // Some fetch API fetching articles}
const politicalArticles = createResource(fetchArticles);
function Content() { const result = politicalArticles.read(someKey); return <div>Article</div>;}
const Articles = () => { return ( <div> <Suspense fallback={<div>loading...</div>}> <Content /> </Suspense> </div> );};
export default Articles;
复制代码


react-cache 中的 createResource 从回调中创建资源,返回一个 promise。


所以只要一个 promise 就能让 Suspense 知道它必须显示加载状态;在 promise 被解析之前它将一直显示加载状态。


但这个功能还处于实验阶段。所以就算你遇到了错误也不用慌张,因为 react-cache 仍处于开发阶段。


需要注意,一定要在组件内部使用 read 方法;否则它会抛出一个错误。


// A snippet from the React-cache library
function readContext(Context, observedBits) { const dispatcher = ReactCurrentDispatcher.current; if (dispatcher === null) { throw new Error( 'react-cache: read and preload may only be called from within a ' + "component's render. They are not supported in event handlers or " + 'lifecycle methods.', ); } return dispatcher.readContext(Context, observedBits);}
复制代码


点击此处查看react-cache源代码


总结

现在我们已经了解了 React 未来的发展趋势,有一件事可以确定:React 团队想要让 API 变得越来越简单。


我也很高兴能看到越来越多的库开始支持函数编程。这种模式肯定会彻底改变我们前端的编程方式。我也在关注 React 的并发改进——相关内容可查看官方文档。React-cache 和 Suspense 就是属于并发 react 的功能。


英文原文:https://blog.logrocket.com/the-future-of-react-unfolding-with-suspense/



2019 年 6 月 16 日 14:228092

评论

发布
暂无评论
发现更多内容

网络直播打赏背后的套路:刺激用户不理智消费

石头IT视角

Java-技术专题-时间工具类的使用方案

李浩宇/Alex

Scrapy 源码剖析(三)Scrapy有哪些核心组件?

Kaito

Python 爬虫 Scrapy 源码剖析

【架构师训练营 1 期】第六周作业

诺乐

Redis还可以做哪些事?

Java旅途

redis

给打工人熬一锅「毒」鸡汤

Java_若依框架教程

程序员 打工人 毒鸡汤

5G应用的实时决策

VoltDB

5G 物联网 工业互联网 技术分享

JAVA魅力之神奇的数组带给你不一样的乐趣

小Q

Java 学习 架构 面试 数组

基于服务设计的线上展览

京东科技开发者

云安全

Flink State 误用之痛,你中招了吗?

Apache Flink

flink

队列实现栈的3种方法,全都击败了100%的用户!

王磊

Java 算法和数据结构

1分钟教你如何整理 React 知识体系

Leo

学习 前端 React 前端进阶训练营

轻量型GPU应用首选 京东智联云推出NVIDIA vGPU实例

京东科技开发者

人工智能 gpu

酷睿i5-10600KF对标锐龙7 3700X,游戏表现领先且售价更香

商业资讯

Scrapy 源码剖析(二)Scrapy是如何运行起来的?

Kaito

Python 爬虫 Scrapy 源码剖析

java安全编码指南之:文件和共享目录的安全性

程序那些事

代码规范 java安全 java安全编码指南 java编码 程序那些事

训练营第二周课程总结

爱码士

训练营

进“大厂”的故事

北风

职业规划 职业成长 大厂

为什么 React Hooks 优于 HOCs(译)

西贝

Java 翻译 React Hooks HOC

接口测试(apipost、jmeter和python脚本)

测试人生路

Python 接口测试 测试工具

Go 与异步 IO - io_uring 的思考

IceberGu

golang Linux 异步IO io_uring

训练营第二周作业

爱码士

TCP/IP 基础知识总结

cxuan

后端 计算机网络 计算机

Scrapy 源码剖析(四)Scrapy如何完成抓取任务?

Kaito

Python 爬虫 Scrapy 源码剖析

老板下了死命令,要把日志系统切换到Logback

沉默王二

Java logback 日志系统

元模型驱动(二)构建元模型ーGME构建分层模型

KaYa

DDD Kaya MDA GME MDD

面试官:讲一下缓存穿透、缓存雪崩和缓存击穿?

bigsai

redis 缓存穿透 缓存击穿 缓存雪崩

【架构师训练营 1 期】第六周学习总结

诺乐

从零实现一个动态表单设计(编辑)器

徐小夕

Java 编辑器 H5 Node React

元模型驱动(一)构建元模型ーGME入门

KaYa

DDD Kaya MDA GME MDD

丑陋的程序员

陆陆通通

程序员 职场 认知

React的未来:与Suspense共舞-InfoQ