1. 为什么需要重新理解useQuery
在React生态中,数据获取一直是个令人头疼的问题。我见过太多项目里充斥着这样的代码:在useEffect里写fetch调用,手动管理loading状态,处理错误,还要考虑缓存和依赖更新。这些重复劳动不仅浪费时间,还容易引入难以追踪的bug。
React Query的出现改变了这一切。它的useQuery钩子将数据获取抽象成了一个声明式的接口,开发者只需关心"要什么数据",而不必操心"怎么获取数据"。但真正理解它的工作原理,远比简单调用API更有价值。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. useQuery的核心设计思想
2.1 查询键(Query Key)的魔法
查询键是React Query最精妙的设计之一。它不仅仅是一个字符串ID,而是一个可序列化的数组,能够精确描述你的数据依赖。比如:
javascript复制useQuery(['todos', { status: 'done' }], fetchTodos)
这个键由两部分组成:'todos'作为基础标识,{ status: 'done' }作为查询变量。React Query会基于这个键自动管理缓存,当组件重新渲染时,如果键不变就直接返回缓存数据。
2.2 状态管理的自动化
传统数据获取需要手动维护多个状态:
javascript复制const [data, setData] = useState(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
useQuery将这些状态统一封装在一个对象中:
javascript复制const { data, isLoading, isError, error } = useQuery(...)
更关键的是,这些状态的更新是原子性的,不会出现loading为false但data还是null的中间状态。
3. 从零实现基础版useQuery
3.1 基本骨架搭建
我们先实现最基础的版本:
javascript复制function useQuery(queryKey, queryFn) {
const [state, setState] = useState({
data: undefined,
isLoading: true,
isError: false,
error: null
})
useEffect(() => {
let isMounted = true
queryFn()
.then(data => {
if (isMounted) {
setState({
data,
isLoading: false,
isError: false,
error: null
})
}
