React Query 查询的三阶段

date
Nov 4, 2025
slug
react-query-stage
status
Published
tags
React Query
summary
React Query 查询的三阶段
type
Post
好了好了,同学们安静!上节课的“共享自习室”还记得吧?咱们学会了怎么用“去重”来避免重复劳动,让组件们学会了“抄作业”的精髓。
今天,咱们要玩点更真实的。
React Query 最神奇的地方之一,就是它能让你写异步代码,感觉就像在写同步代码一样——行云流水,德芙纵享丝滑。但问题是,它只是感觉像,它并不是真的!
这就像你点了一份外卖。在 App 上下单很快,感觉食物已经到手了。但你不能立刻开始吃,对吧?中间有个“等待外卖小哥”的过程。

“幻觉”与现实的碰撞

让我们来搞个新需求:我们要获取用户电脑上所有可用的摄像头、麦克风设备列表。浏览器正好有个 navigator.mediaDevices.enumerateDevices() API,它返回一个 Promise,完美!
凭着我们对 React Query 的了解,我们可能会“想当然”地写出这样的代码:
看起来很美,不是吗?queryFn 返回一个 Promise,React Query 搞定一切,我们直接用 data 就好了。
但如果你真的运行这段代码,迎接你的将是一个鲜红的错误:
Cannot read properties of undefined (reading 'map')
这是新手最常踩的坑,没有之一!
为什么?因为 React Query 不是时间机器!它无法瞬间变出数据。在你调用 useQuery 的那一刻,到 queryFn 里的 Promise 完成之前,有一段“真空期”。在这段时间里,data 是什么?是 undefined
你试图在一个 undefined 上调用 .map() 方法,这就像你对着空气说:“嘿,空气,给我变个披萨出来!” JavaScript 引擎只会一脸懵逼地看着你,然后给你报个错。

救星登场:查询的“人生三阶段”

那么,我们怎么知道外卖送到哪一步了呢?很简单,看外卖 App 上的状态啊!“正在备餐”、“骑手已取货”、“正在派送”...
React Query 也为我们提供了这样一个“状态追踪器”。每一个查询(Query),都有它清晰的“人生三阶段”,这完全对应了 Promise 的三种状态:
  1. pending (等待中):查询已经发出,正在路上,我们还没有拿到数据。就像外卖 App 上的“正在备餐”。此时 dataundefined
  1. success (已成功):查询成功返回,数据已到手!就像外卖 App 上的“订单已送达”。此时 data 是可用的。
  1. error (出错了):查询失败了,可能网络断了,或者服务器宕机了。就像外卖 App 提示“商家关门,订单取消”。此时 data 还是 undefined,但你会得到一个 error 对象。
我们有两种方式来获取这个状态。

方式一:直截了当的 status 属性

useQuery 会直接返回一个 status 字符串,告诉你当前处于哪个阶段。
看,通过判断 status,我们为用户提供了完美的加载和错误提示,那个恼人的 undefined 错误也随之消失了。

方式二:更具“风味”的布尔值标志

如果你觉得写字符串比较麻烦,React Query 还提供了一套派生出来的布尔值,用起来更像是开关。
  • isPending (是不是在 pending?)
  • isSuccess (是不是 success 了?)
  • isError (是不是 error 了?)
代码就变成了这样:
status 还是用 isPending/isError?这纯粹是个人口味问题。就像你喜欢用 tabs 还是 spaces 一样。你可以随便选一个,然后在和同事的代码审查(Code Review)中,为你的选择据理力争、捍卫尊严!
Promise 状态
查询人生阶段
status 属性
is 系列布尔值
Pending
等待中
'pending'
isPending: true
Fulfilled
已成功
'success'
isSuccess: true
Rejected
出错了
'error'
isError: true

给 TypeScript 同学的悄悄话

这里有个更酷的魔法。useQuery 的返回对象是一个“可区分联合类型”。
说人话就是:TypeScript 非常聪明!
当你写下 if (isPending) 或者 if (status === 'error') 这样的判断后,在这些代码块的内部,TypeScript 知道 data 肯定是 undefined
而一旦你排除了所有这些可能性,在剩下的代码里(也就是成功状态下),TypeScript 会自动把 data 的类型从 MediaDeviceInfo[] | undefined 收窄MediaDeviceInfo[]。它知道,外卖送到家了,那手里拿的就一定是披萨,不可能是“披萨或者空气”!这个过程叫**“类型收窄”**,让你在写代码时享受极致的类型安全和自动补全。

课堂总结

好了同学们,今天的核心知识点就是:
  1. 警惕异步幻觉:React Query 虽好,但它不是时间机器。数据需要时间才能到达。
  1. 拥抱生命周期:所有查询都有 pendingsuccesserror 三个阶段。
  1. 做好状态处理:使用 statusisPending/isError 来为用户提供加载和错误界面,这是专业前端的必备素养!
记住,一个优秀的 UI,不仅要展示成功的结果,更要优雅地处理等待和失败。现在,你已经掌握了构建健壮异步界面的关键钥匙。
下课!去把你们代码里那些裸奔的 data.map 都抓起来,给它们穿上 isPending 的加载外套和 isError 的错误提示吧!

© 拾光 2025 - 2026

粤ICP备2025472574号