TanStack Query
TanStack Query(原 React Query)是一个强大的异步状态管理器,支持多个前端框架,包括 React、Vue、Solid 等。
核心概念
- Queries: 用于数据获取
- Mutations: 用于数据修改
- Query Invalidation: 查询失效处理
- Caching: 缓存机制
- Background Updates: 后台更新
- Optimistic Updates: 乐观更新
React 使用
1. 安装和配置
npm install @tanstack/react-query
// App.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5分钟
cacheTime: 1000 * 60 * 30, // 30分钟
},
},
});
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
2. 基本查询
import { useQuery } from '@tanstack/react-query';
function TodoList() {
const { data, isLoading, error } = useQuery({
queryKey: ['todos'],
queryFn: () => fetch('/api/todos').then(res => res.json()),
staleTime: 5000,
cacheTime: 300000,
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}
3. 带参数的查询
function Todo({ todoId }) {
const { data, isLoading } = useQuery({
queryKey: ['todo', todoId],
queryFn: () => fetchTodoById(todoId),
enabled: !!todoId,
});
if (isLoading) return <div>Loading...</div>;
return <div>{data.title}</div>;
}
4. 修改数据
import { useMutation, useQueryClient } from '@tanstack/react-query';
function AddTodo() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (newTodo) => {
return fetch('/api/todos', {
method: 'POST',
body: JSON.stringify(newTodo),
});
},
onSuccess: () => {
// 使相关查询失效
queryClient.invalidateQueries({ queryKey: ['todos'] });
},
});
return (
<form onSubmit={(e) => {
e.preventDefault();
mutation.mutate({ title: 'New Todo' });
}}>
<button type="submit">Add Todo</button>
</form>
);
}
5. 乐观更新
function TodoList() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: updateTodo,
onMutate: async (newTodo) => {
// 取消任何传出的重新获取
await queryClient.cancelQueries({ queryKey: ['todos'] });
// 获取之前的值
const previousTodos = queryClient.getQueryData(['todos']);
// 乐观更新
queryClient.setQueryData(['todos'], (old) => {
return old.map(todo =>
todo.id === newTodo.id ? newTodo : todo
);
});
// 返回上下文
return { previousTodos };
},
onError: (err, newTodo, context) => {
// 发生错误时回滚
queryClient.setQueryData(['todos'], context.previousTodos);
},
});
}