文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

React 中,最优雅的异步请求解决方案:use + Suspense

2024-11-29 18:42

关注

当然,他的正式版还没有发布。不过 RC 版更新非常频繁,基本上两三天就会发一个版本

虽然有部分项目没有把 React 升级到 19 这个版本,但是我也将 React 19 中提到的开发思维抽离了出来,在低版本中使用。

这篇文章继续给大家分享在 React 19 中使用 use + Suspense 来处理异步请求为什么是目前我见过的更优雅的解决方案。

一、传统方案

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

在 react 传统的方案中,我们将数据和 Loading 定义在不同的 state 中,然后通过判断 Loading 状态的变化,来识别应该返回什么样的 UI 结果,然后借助 useEffect 来请求接口。

代码大概如下所示:

很明显,每个页面都这样干的话,会比较繁琐。因此,我们通常会通过自定义 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 
  }

  return (
    
  )
}

大家常用的 ahooks,useQuery 等,都是这个封装思路。

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

function Index2() {
  const {content, loading} =  useFetch()

  return (
    
  )
}

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

function Index2() {
  const {content, loading} =  useFetch()

  return (
    
      
    
  )
}

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

刚开始使用这种方式时,我也非常惊讶,原来异步请求的逻辑处理可以整理得这么简洁,这么得体。但是随着使用经验的增加,也处理了更多的场景,几乎绝大多数场景都能够平滑的应对,但是我依然发现这种方式存在一些小小的痛点。

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

function useFetch(params) {
  ...
}

常见的变化量包括:

当不同的东西开始变得越来越多,我逐渐发现一个事情,那就是优雅正在消失...

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

二、React 19 的新方案

让我感觉到比较惊喜的是,React 19 提出了一个新的方式,让我们应对这些复杂场景变得更加简单。那就是 use + promise + Suspense。

首先来简单学习一下 React19 中的做法。

首先,我们会把数据存储在 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() {
  _api({value: 20})
}

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

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

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

export default function Index() {
  const [promise, setPromise] = useState(_api3)
  return (
    }>
      
    
  )
}

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

const Message = (props) => {
  const content = use(props.promise)
  return (
    
...
) }

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

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

认真体会这段代码的优雅性。

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

我们可以非常自由的在不同的场景处理参数。例如,有的地方可能需要缓存上一次的参数,但是有的地方不需要。那么,需要缓存的场景,我们随便单独缓存即可。

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

三、总结

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

现在 react19 正式版本还没有发布,加上热衷于使用 react19 的博主只有我一个,因此这种方案目前只是在很小的范围内被使用,成为主流可能还需要一点时间的传播和学习。

来源:这波能反杀内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯