React18中请求数据的官方姿势适用其他框架

目录
  • 引言
  • 这是一个普遍的问题
  • 为什么不推荐这么写?
    • 需要解决竞态问题
    • 点击返回按钮后重新请求数据
    • CSR时的白屏时间
    • 瀑布问题
    • 推荐的方式
  • 总结

引言

一些同学喜欢在useEffect中请求初始数据,类似这样:

useEffect(() => {
  fetch(xxx).then(data => setState(data.json()))
}, [])

React18并不推荐这种方式。

这么写有什么问题?如果不推荐这种方式,那么推荐的方式是什么呢?

本文来看看Danreddit是如何回答上述问题的。

这是一个普遍的问题

除了React外,大部分以组件形式组织的前端框架,都有如下类似的API

effect

didMount/didUpdate

如果有初始化时请求数据的需求,这类框架都会选择在上述回调函数内执行请求操作,并在数据返回后更新状态。

所以,这并不是React独有的问题。相反,他很普遍。

之所以在React中这么突出,是因为React官方在引导开发者不要用这种形式书写代码(通过严格模式下useEffect执行两次放大这个问题)。

React之所以这么做,是为了项目的性能以及UX(User Experience,用户体验)。

下面我们来细聊这么做的影响。注意,这些影响同样适用于其他框架。

为什么不推荐这么写?

需要解决竞态问题

useEffect中请求数据要面临的第一个问题是需要解决竞态问题

假设你有个组件User,接收userID作为props,用userID请求数据后展示用户信息。

下面是你的写法:

function User({userID}) {
  const [data, setData] = useState(null);
  useEffect(() => {
    const res = await fetch(`https://xxx/${userID}/`);
    setData(res.json());
  }, [userID]);
  if (data) {
    return <div>{data.name}</div>;
  }
  return null;
}

这里有个开发阶段很难复现的bug —— 如果userID变化足够快,会发起多个不同的用户请求。

而最终展示哪个用户的数据,取决于哪个请求先返回。这就是请求的竞态问题

点击返回按钮后重新请求数据

如果用户跳转到新的页面后,又通过浏览器回退按钮回到当前页面,并不能立刻看到他跳转前的页面。

相反,看到的可能是个白屏 —— 因为还需要重新执行useEffect获取初始数据。

这个问题的本质原因是:没有初始数据的缓存。

CSR时的白屏时间

CSR(Client-Side Rendering,客户端渲染)时在useEffect中请求数据,在数据返回前页面都是白屏状态。

瀑布问题

如果父子组件都依赖useEffect获取初始数据渲染,那么整个渲染流程如下:

  • 父组件mount
  • 父组件useEffect执行,请求数据
  • 数据返回后重新渲染父组件
  • 子组件mount
  • 子组件useEffect执行,请求数据
  • 数据返回后重新渲染子组件

可见,当父组件数据请求成功后子组件甚至还没开始首屏渲染。

这就是渲染中的瀑布问题 —— 数据像瀑布一样一级一级向下流动,流到的组件才开始渲染,很低效。

既然直接写useEffect有这么多问题,那么推荐的方式是什么呢?

推荐的方式

Meta公司内部,基于Relay驱动数据(但请求数据要求使用GraphQL),所以这套架构比较难在社区普及开。

但是,现在社区已经有了成熟的请求数据的方案

对于SSR,可以使用Next.jsRemix接管数据请求。

对于CSR,可以使用React QueryuseSWR接管数据请求。

这些成熟的方案都致力于解决上述提到的问题。

如果不想使用这些方案,想自己写,可以参考React新文档中下面两篇文章:

使用effect同步数据

你可能不需要使用effect

想看中文的同学,可以看我写的总结 —— React新文档:不要滥用effect哦

总结

本文我们聊了React18之后不推荐的请求数据的方式以及推荐的请求数据的方式。

其中不推荐的请求数据的方式不仅存在于React中,很多前端框架都有这样的问题。

以上就是React18中请求数据的官方姿势适用其他框架的详细内容,更多关于React18请求数据的资料请关注我们其它相关文章!

(0)

相关推荐

  • React18之状态批处理的使用

    目录 状态自动批处理 17版 18版 退出状态自动批处理 要点概述 react在3月29号正式发布了18版本, 此次更新包括: 状态自动批处理, 客户端渲染api的更新, 新的hook等很多变化, 本章先说一下状态批处理的变化. React v18.0 – React Blog 状态自动批处理 18版本之前, 在合成事件之外的原生事件中(例如 setTimeout, onclick, promise) , 更新状态并不会进行批量处理(合并), 这意味着在原生事件中多次调用状态更新会造成多次应用的

  • React18中的useDeferredValue示例详解

    目录 有什么用? 实操起来 跟防抖的区别 接着上一篇React18的简介和自动批处理的特性,今天我们来聊下useDeferredValue. 有什么用? lets you defer updating the less important parts of the screen 我们翻译下,允许用户推迟屏幕更新优先级不高部分. 说“人话”就是,如果说某些渲染比较消耗性能,比如存在实时计算和反馈,我们可以使用这个Hook降低其计算的优先级,使得避免整个应用变得卡顿. 较多的场景可能就在于用户反馈输

  • React18新增特性released的使用

    目录 新功能:Automatic Batching 新功能:Transitions 新的Suspense功能 新的客户端和服务器Rendering APIs React DOM Client React DOM Server 新的Strict Mode Behaviors 新Hooks React 18 中的新增功能 新功能:Automatic Batching 批处理是指 React 将多个状态更新分组到单个重新呈现中以获得更好的性能.在没有自动批处理的情况下,我们只在 React 事件处理程

  • react18中react-redux状态管理的实现

    react的状态管理还是挺多的现在流行的有以下五种: Recoil MobX XState Redux Context 今天我们来讲一下react众多状态管理之一的redux,虽然这个我不太喜欢用,但是我觉得简单的状态管理谁都会,但是难的就是程序员的分水岭,所以今天来给大家讲一下redux. 下面我们来讲讲redux的优点: 可以在众多组件中传值,突破react单向数据流的限制 不仅支持react还支持vue等主流框架 当然是好用方便啦 接下来我们讲一下啥时候去使用他 在我们有好多组件,但是组件

  • React18中请求数据的官方姿势适用其他框架

    目录 引言 这是一个普遍的问题 为什么不推荐这么写? 需要解决竞态问题 点击返回按钮后重新请求数据 CSR时的白屏时间 瀑布问题 推荐的方式 总结 引言 一些同学喜欢在useEffect中请求初始数据,类似这样: useEffect(() => { fetch(xxx).then(data => setState(data.json())) }, []) 但React18并不推荐这种方式. 这么写有什么问题?如果不推荐这种方式,那么推荐的方式是什么呢? 本文来看看Dan在reddit是如何回答

  • vue中在vuex的actions中请求数据实例

    我废话不多说了,直接上代码吧! actions.js getCertificationStatus(context, {vm:vm,type:type}){ return new Promise((resolve, reject) => { axios.post('/realNameUtils/gotoStatusPage') .then((res)=>{ context.commit('certificationStatus',res.data.content) if(type=='1'){

  • 谈一谈vue请求数据放在created好还是mounted里好

    建议放在created里 created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图. mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作. 如果在mounted钩子函数中请求数据可能导致页面闪屏问题 其实就是加载时机问题,放在created里会比mounted触发早一点,如果在页面挂载完之前请求完成的话就不会看到闪屏了 补充知识:vue各阶段数据可使用情况:created,computed,data,prop

  • 详解在vue-cli项目中使用mockjs(请求数据删除数据)

    在我们的生产实际中,后端的接口往往是较晚才会出来,于是我们的前端的许多开发都要等到接口给我们才能进行,这样对于我们前端来说显得十分的被动,于是有没有可以制造假数据来模拟后端接口呢,答案是肯定的.于是今天我们来介绍一款非常强大的插件Mock.js,可以非常方便的模拟后端的数据,也可以轻松的实现增删改查这些操作,在后台数据完成之后,你所做的只是去掉mockjs:停止拦截真实的ajax,仅此而已. 搭建一个vue项目 # 全局安装 vue-cli $ npm install --global vue-

  • 基于iframe实现ajax跨域请求 获取网页中ajax数据

    大家都知道,在不同域的情况下是不能发送ajax请求的,浏览器会报如下错误: 同时,内嵌的iframe中无法进行跨域通信的,也就是说不同域的iframe是无法互相读取数据的(当然利用hash变化可以从父window传入数据到子iframe,不过并没有什么意义).iframe跨域通信时,浏览器会报如下错误: 其实这两个问题都是由于跨域造成的. 下面就介绍如何解决这个问题. 其实问题的关键就在于,浏览器在解析ajax请求地址时会和当前网页的地址进行比较,如果是跨域的,那就禁止掉并且报错.那么我们如果让

  • vue中promise的使用及异步请求数据的方法

    下面给大家介绍vue中promise的使用 promise是处理异步的利器,在之前的文章<ES6之promise>中,我详细介绍了promise的使用, 在文章<js动画实现&&回调地狱&&promise>中也提到了promise的then的链式调用, 这篇文章主要是介绍在实际项目中关于异步我遇到的一些问题以及解决方法,由此来加深对promise的进一步理解. 背景 进入商品页,商品页的左侧是分类,右侧是具体的商品,一旦进入商品页,就把所有分类的商品

  • vue中实现先请求数据再渲染dom分享

    在项目中遇到了一个问题,下面是vue template中的代码: 我之前的写法是 这样做的结果是下面取dom的操作,取到的dom都是undefined,也就是没有取到. 原因是并没有按照 请求数据->渲染dom->获取dom的顺序执行,实际的执行顺序是 先获取dom,而此时数组option中还是空的,上面的v-for循环也就没有渲染出dom,所以根本取不到(不理解是为什么) 后来我又把请求数据写在了created函数中,把取dom的操作写在mounted函数中,竟然还是先执行取dom的操作(是

  • 在python中使用requests 模拟浏览器发送请求数据的方法

    如下所示: import requests url='http://####' proxy={'http':'http://####:80'} headers={ "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Accept-Lang

  • SpringMVC 重新定向redirect请求中携带数据方式

    目录 SpringMVC 重新定向redirect请求中携带数据 使用URL模版重定向 使用flash属性 SpringMVC 几种重定向携带数据方法 1.拼接字符串 2.采用RedirectAttribute来传参数 3.RedirectAttribute-–addFlashAttribute()的用法 SpringMVC 重新定向redirect请求中携带数据 在控制器方法返回的视图名称中使用了redirect:前缀,这时返回的String不是用来寻找视图,而是浏览器进行跳转的路径: ret

  • python获取http请求响应头headers中的数据的示例

    例如我要测试一个创建网络的接口,需要先拿token值,而获取token的接口请求成功后,将token存在了响应头headers,postman调接口如下,现在想要通过python获取下图中 X-Subject-Token的值,供后续接口使用 方法:仅需要python的requests库就可以实现 示例: #!/usr/bin/env python # -*- coding: utf-8 -*- # @File : 1.py # @Author: ttwang # @Date : 2022/2/1

随机推荐