React中最优雅的异步请求

给大家分享在React19中使用use+Suspense处理异步请求为什么是被认为最优雅的解决方案

一. 传统方案

解决异步请求的方案中,我们要处理至少两个最基本的逻辑

  1. 正常的数据显示
  2. 数据加载的UI状态

例如:

export default function Index(){const [content, update] = useState({value: ''})const [loading, setLoading] = useState(true)useEffect(() => {api().then(res => {setLoading(false)update(res)})}, []);if (loading) {return <Skeleton/>}return (<Message message={content.value}/>)
}

很明显,每个页面都这样干的话,会比较繁琐。因此,通常会通过自定义hook的方式封装请求逻辑简化每个页面的代码

function useFetch() {const [content, update] = useState({value: ''})const [loading, setLoading] = useState(true)useEffect(() => {api().then(res => {setLoading(false)update(res)})}, []);return {content,loading}
}

这样,页面代码就变成了如下更简洁的形式

function index2() {const {content, loading} = useFetch()if(loading) {return <Skeleton/>}return (<Message message={content.value}/>)
}

✅ 常用的ahooks、useQuery等,都是这个封装思路

在UI层面,我们还可以做一层封装,把loading封装到UI组件逻辑中去。常见的使用方式可以是这样

function Index2() {const {content, loading} = useFetch()return (<Messagemessage={content.value}loading={loading}/>)
}

也可以参考antd中,Spin的使用方式

function Index2() {const {content, loading} = useFetch()return (<Spin tip="Loading..."><Messagemessage={content.value}/></Spin>)
}

img

通过这样的两步优化让我们页面代码变得非常简洁。这也是日常使用最多的方式,开发效率也非常高。

但随着使用经验的增加,也处理了更多的场景,几乎绝大多数场景都能够平滑的应对,但这种方式依旧存在一些小小的痛点。

当在思考如何封装usefetch 时,首先会考虑清楚在众多场景之下,有哪些东西是变化量。变化的内容我们将其设计为参数传入

function useFetch(params) {}

常见的变化量包括:入参不同请求方式不同返回类型不同部分场景需要初始的默认值部分场景的接口并不需要立即请求返回结果可能需要二次处理才能正常使用参数变化之后的处理逻辑不同…

当不同的东西开始变得越来越多,优雅也在逐渐消失…

✅ 当前这肯定有对应的成套架构解决方案,到那时对于普通开发者来说变得有点难度,需要更丰富的经验来支撑才能应对各种不同的场景。

二. React 19的新方案

React19提出了一个新的方式,让我们应对这些复杂场景变得更加简单。那就是use + promise + Suspense

首先会把数据存储在promise中。然后promise定义为state

const _api3 = (params) => {return new Promise(resolve => {resolve({ value: 'React does not preserve any state for renders that got suspended before they were able to mount for the first time. When the component has loaded, React will retry rendering the suspended tree from scratch.' })})
}
const [promise, setPromise] = useState(_api3)

如果有默认参数需要传入,只需要在执行 _api3 时传入参数即可

const promise = useState(() => _api3({value: 10}))

如果我们在点击时,需要修改参数并且重新请求接口,可以一样重新执行_api3即可

function clickHandler(){_api3({value: 20})
}

由于触发UI更新必须借助state的变化,因此每次将_api3 执行返回的promise存储在useState中,点击时,_api3的执行结果必定是新的promise对象,因此,代码更改为如下,即可触发UI的更新

function clickHandler(){setPromise(_api3({value: 20}))
}

然后,将promise传入到具体的UI组件中去,并使用 Suspense 包裹起来

export default function Index() {const [promise, setPromise] = useState(_api3)return (<Suspense fallback={<Skeleton />}><Message promise={promise} /></Suspense>)
}

然后在 UI 组件内部,使用 use 获取 promise 中的数据即可

const Message = (props) => {const content = use(props.promise)return (<div className='flex border border-blue-100 p-4 rounded-md shadow'>...</div>)
}

在这套解决方案之下,参数的多变性处理起来就变得非常容易,可以直接控制参数是否变化,也可以直接控制接口是否需要重新请求。

只需要按照需求,在响应实践中执行对应的逻辑就可以了,而不需要像上面那种方案一样,还要额外封装,否则代码会变得更乱

function clickHandler() {
setPromise(_api({value: 20}))
}

认真体会这段代码的优越性,可以非常自由的在不同的场景处理参数。例如,有的地方可能需要缓存上一次的参数,但是有的地方不需要。那么需要缓存的场景,可以随便单独缓存即可。

也不用受限于参数的变化是否会引发接口的重新请求,这里参数的变化与接口的执行被解耦开,直接由我们开发时控制

三. 总结

很显然,react19 中提到的解决异步逻辑的方案,是目前为止,被认为是最优雅的方案。这种方案不需要我们再进一步二次封装,就能够轻松应对各种复杂的场景。这必将成为未来开发的主流方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/65347.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库高安全—openGauss安全整体架构安全认证

openGauss作为新一代自治安全数据库&#xff0c;提供了丰富的数据库基础安全能力&#xff0c;并逐步完善各类高阶安全能力。这些安全能力涵盖了访问登录认证、用户权限管理、审计与追溯及数据安全隐私保护等。本章节将围绕openGauss安全机制进行源码解读&#xff0c;以帮助数据…

linux-23 文件管理(一)创建文件touch,stat

那接下来看看文件的创建和删除&#xff0c;那我们怎么去创建一个文件&#xff1f;各种方式都能实现&#xff0c;当然&#xff0c;这里先说一说&#xff0c;就像mkdir创建空目录一样&#xff0c;我们如何创建一个空文件&#xff1f;创建空文件其实很简单&#xff0c;有一个命令歪…

Linux 基本指令

目录 1.常见指令 1.1 ls指令 1.2 pwd指令 1.3 cd指令 1.4 touch指令 1.5 mkdir指令 1.6 rm和rmdir指令 1.7 man指令 1.8 cp指令 1.9 mv指令 ​编辑 1.10 cat指令 1.11 more指令 1.12 less指令 1.13 head指令 1.14.tail指令 1.15 时间相关的指令 1.16 cal…

金蝶V10中间件的使用

目录 环境准备搭建过程配置修改应用部署 环境准备 Linux内核服务器JDK1.8安装包&#xff1a;AAS-V10.zip程序包&#xff1a;***.war 搭建过程 将安装包上传至服务器opt目录下&#xff0c;官方给定的默认服务主目录为“/opt/AAS-V10/ApusicAS/aas/”&#xff1b;解压安装包(解…

前端开发 -- 自动回复机器人【附完整源码】

一&#xff1a;效果展示 本项目实现了一个简单的网页聊天界面&#xff0c;用户可以在输入框中输入消息&#xff0c;并点击发送按钮或按下回车键来发送消息。机器人会根据用户发送的消息内容&#xff0c;通过关键字匹配来生成自动回复。 二&#xff1a;源代码分享 <!DOCTYP…

Python数据可视化小项目

英雄联盟S14世界赛选手数据可视化 由于本学期有一门数据可视化课程&#xff0c;课程结课作业要求完成一个数据可视化的小Demo&#xff0c;于是便有了这个小项目&#xff0c;课程老师要求比较简单&#xff0c;只要求熟练运用可视化工具展示数据&#xff0c;并不要求数据来源&am…

Linux系统编程——详解页表

目录 一、前言 二、深入理解页表 三、页表的实际组成 四、总结&#xff1a; 一、前言 页表是我们之前在讲到程序地址空间的时候说到的&#xff0c;它是物理内存到进程程序地址空间的一个桥梁&#xff0c;通过它物理内存的数据和代码才能映射到进程的程序地址空间中&#xff…

【Java数据结构】LinkedList与链表

认识LinkedList LinkedList就是一个链表&#xff0c;它也是实现List接口的一个类。LinkedList就是通过next引用将所有的结点链接起来&#xff0c;所以不需要数组。LinkedList也是以泛型的方法实现的&#xff0c;所以使用这个类都需要实例化对象。 链表分为很多种&#xff0c;比…

《一文读懂卷积网络CNN:原理、模型与应用全解析》

《一文读懂卷积网络CNN&#xff1a;原理、模型与应用全解析》 一、CNN 基本原理大揭秘&#xff08;一&#xff09;从人类视觉到 CNN 灵感&#xff08;二&#xff09;核心组件详解 二、经典 CNN 模型巡礼&#xff08;一&#xff09;LeNet-5&#xff1a;开山鼻祖&#xff08;二&a…

教育元宇宙的优势与核心功能解析

随着科技的飞速发展&#xff0c;教育领域正迎来一场前所未有的变革。教育元宇宙作为新兴的教育形态&#xff0c;以其独特的优势和丰富的功能&#xff0c;正在逐步改变我们的学习方式。本文将深入探讨教育元宇宙的优势以及其核心功能&#xff0c;为您揭示这一未来教育的新趋势。…

openGauss与GaussDB系统架构对比

openGauss与GaussDB系统架构对比 系统架构对比openGauss架构GaussDB架构 GaussDB集群管理组件 系统架构对比 openGauss架构 openGauss是集中式数据库系统&#xff0c;业务数据存储在单个物理节点上&#xff0c;数据访问任务被推送到服务节点执行&#xff0c;通过服务器的高并…

idea 8年使用整理

文章目录 前言idea 8年使用整理1. 覆盖application配置2. 启动的时候设置编辑空间大小&#xff0c;并忽略最大空间3. 查询类的关系4. 查看这个方法的引用关系5. 查看方法的调用关系5.1. 查看被调用关系5.2. 查看调用关系 6. 方法分隔线7. 选择快捷键类型8. 代码预览插件9. JReb…

C++ OCR 文字识别

一.引言 文字识别&#xff0c;也称为光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;是一种将不同形式的文档&#xff08;如扫描的纸质文档、PDF文件或数字相机拍摄的图片&#xff09;中的文字转换成可编辑和可搜索的数据的技术。随着技…

SQL中的窗口函数

1.窗口函数简介 窗口函数是SQL中的一项高级特性&#xff0c;用于在不改变查询结果集行数的情况下&#xff0c;对每一行执行聚合计算或者其他复杂的计算&#xff0c;也就是说窗口函数可以跨行计算&#xff0c;可以扫描所有的行&#xff0c;并把结果填到每一行中。这些函数通常与…

SpringBoot(Ⅱ)——@SpringBootApplication注解+自动装配原理+约定大于配置

1. SpringBootApplication注解 SpringBootApplication标注在某个类上说明这个类是SpringBoot的主配置类&#xff0c;SpringBoot就通过运行这个类的main方法来启动SpringBoot应用&#xff1b; 并且Configuration注解中也有Component注解&#xff0c;所以这个主启动类/主配置类…

音视频入门知识(二)、图像篇

⭐二、图像篇 视频基本要素&#xff1a;宽、高、帧率、编码方式、码率、分辨率 ​ 其中码率的计算&#xff1a;码率(kbps)&#xff1d;文件大小(KB)&#xff0a;8&#xff0f;时间(秒)&#xff0c;即码率和视频文件大小成正比 YUV和RGB可相互转换 ★YUV&#xff08;原始数据&am…

CTFshow—爆破

Web21 直接访问页面的话会弹窗需要输入密码验证&#xff0c;抓个包看看&#xff0c;发现是Authorization认证&#xff0c;Authorization请求头用于验证是否有从服务器访问所需数据的权限。 把Authorization后面的数据进行base64解码&#xff0c;就是我们刚刚输入的账号密码。 …

lin.security提权靶场渗透

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

【魅力golang】之-泛型

早期的golang版本是不支持泛型的&#xff0c;这对于从其它语言转型做go开发的程序员来说&#xff0c;非常不友好&#xff0c;自 1.18开始golang正式支持泛型&#xff0c;解决了开发者在编写通用代码时的需求。泛型通过类型参数允许函数和数据结构支持多种类型&#xff0c;从而提…

数据结构(Java)——链表

1.概念及结构 链表是一种 物理存储结构上非连续 存储结构&#xff0c;数据元素的 逻辑顺序 是通过链表中的 引用链接 次序实现的 。 2.分类 链表的结构非常多样&#xff0c;以下情况组合起来就有 8 种链表结构&#xff1a; &#xff08;1&#xff09;单向或者双向 &#xff08;…