
为什么选择 TanStack Query
服务端状态是异步的,可能过时,需要缓存。TanStack Query 处理所有这些。

设置 + useQuery
const [qc] = useState(() => new QueryClient({ defaultOptions: { queries: { staleTime: 60_000 } } }))
function usePost(id) {
return useQuery({
queryKey: ['posts', id],
queryFn: () => fetch('/api/posts/' + id).then(r => r.json()),
enabled: id > 0,
})
}

useMutation + 乐观更新
const mutation = useMutation({
mutationFn: (data) => fetch('/api/posts', { method: 'POST', body: JSON.stringify(data) }).then(r => r.json()),
onMutate: async (newPost) => {
await queryClient.cancelQueries({ queryKey: ['posts'] })
const prev = queryClient.getQueryData(['posts'])
queryClient.setQueryData(['posts'], old => [...(old || []), { ...newPost, id: 'temp' }])
return { prev }
},
onError: (_, __, ctx) => queryClient.setQueryData(['posts'], ctx?.prev),
onSettled: () => queryClient.invalidateQueries({ queryKey: ['posts'] }),
})

无限滚动
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam = 1 }) => fetch('/api/posts?page=' + pageParam).then(r => r.json()),
getNextPageParam: last => last.nextPage,
initialPageParam: 1,
})
const posts = data?.pages.flatMap(p => p.posts) ?? []
-> 使用 JSON Viewer 调试 API 响应。