跳到主要内容

React 使用

React 项目里,TanStack Query 最常见的价值是:把“页面加载一份数据”升级成“数据能缓存、能失效、能重取、能共享”。

基本查询

import { useQuery } from '@tanstack/react-query'

function TodoList() {
const { data, isLoading, error } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
})

if (isLoading) return <div>Loading...</div>
if (error) return <div>Error</div>

return (
<ul>
{data?.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
)
}

带参数的查询

function TodoDetail({ todoId }: { todoId?: string }) {
const { data } = useQuery({
queryKey: ['todo', todoId],
queryFn: () => fetchTodoById(todoId!),
enabled: !!todoId,
})

return <div>{data?.title}</div>
}

enabled 很常用。参数还没准备好时,不要让查询先跑出去。

修改数据

import { useMutation, useQueryClient } from '@tanstack/react-query'

function AddTodo() {
const queryClient = useQueryClient()

const mutation = useMutation({
mutationFn: createTodo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
})

return (
<button onClick={() => mutation.mutate({ title: 'New Todo' })}>
Add
</button>
)
}

一个更常见的项目写法

页面里不要直接写所有 query 逻辑,通常会收成 hooks。

export function useTodoList(params: { keyword?: string }) {
return useQuery({
queryKey: ['todos', params],
queryFn: () => fetchTodoList(params),
})
}

这样页面层拿到的是一个语义明确的业务 hook,而不是一段散着的查询配置。

和请求层配合

import { getUserDetail } from '@/api/user'

export function useUserDetail(id?: string) {
return useQuery({
queryKey: ['user', id],
queryFn: () => getUserDetail(id!),
enabled: !!id,
})
}

这种结构最稳:

  • api/ 负责请求细节
  • query hook 负责缓存和同步
  • 页面负责展示和交互