在实际项目中,合理组织和管理 React Query 的查询对于代码的可维护性和可扩展性至关重要:
项目结构组织
-
查询函数分离
- 将数据获取逻辑从组件中分离出来
- 创建专门的 API 或服务层
- 示例结构:
shell
src/ ├── api/ │ ├── index.js │ ├── users.js │ └── posts.js ├── components/ └── pages/
-
自定义钩子封装
- 创建自定义钩子封装常用查询逻辑
- 提供统一的接口和配置
- 示例:
javascript
// src/hooks/useUsers.js import { useQuery } from 'react-query'; import { fetchUsers } from '../api/users'; export const useUsers = (options = {}) => { return useQuery('users', fetchUsers, { staleTime: 5 * 60 * 1000, ...options, }); };
-
查询键管理
- 创建统一的查询键常量或工具函数
- 确保查询键的一致性和可维护性
- 示例:
javascript
// src/utils/queryKeys.js export const queryKeys = { users: 'users', user: (id) => ['user', id], posts: 'posts', userPosts: (userId) => ['posts', 'user', userId], };
命名约定
-
查询键命名
- 使用描述性的名称
- 对于动态参数,使用数组形式
- 遵循一致的命名模式(如
[resource, id, action])
-
自定义钩子命名
- 使用
use前缀 - 名称应反映查询的用途
- 示例:
useUsers,useUserPosts,useCreateUser
- 使用
-
API 函数命名
- 使用清晰的动词+名词结构
- 示例:
fetchUsers,createUser,updatePost
最佳实践
-
全局配置
- 在应用入口配置 QueryClient
- 设置合理的默认选项
- 示例:
javascript
// src/App.js import { QueryClient, QueryClientProvider } from 'react-query'; const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 30000, cacheTime: 60000, retry: 2, }, }, }); function App() { return ( <QueryClientProvider client={queryClient}> {/* 应用组件 */} </QueryClientProvider> ); }
-
查询分组和层次结构
- 使用层次化的查询键
- 便于批量操作和失效
- 示例:
javascript
// 层次化查询键 const userQueryKey = ['users', userId]; const userPostsQueryKey = ['users', userId, 'posts']; // 批量失效 queryClient.invalidateQueries(['users', userId]);
-
代码分割和懒加载
- 对于大型应用,考虑代码分割
- 按需加载查询逻辑
-
测试策略
- 模拟 QueryClient 和查询响应
- 测试组件在不同查询状态下的表现
- 示例:
javascript
// 使用 React Testing Library import { render, screen } from '@testing-library/react'; import { QueryClient, QueryClientProvider, useQuery } from 'react-query'; test('renders data when query succeeds', async () => { const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: Infinity, }, }, }); // 预填充缓存 queryClient.setQueryData('todos', [{ id: 1, title: 'Test Todo' }]); render( <QueryClientProvider client={queryClient}> <TodoList /> </QueryClientProvider> ); expect(await screen.findByText('Test Todo')).toBeInTheDocument(); });
-
文档和注释
- 为复杂查询添加注释
- 记录查询的用途、缓存策略和依赖关系
通过遵循这些最佳实践,可以创建更加结构化、可维护和可扩展的 React Query 代码库,提高开发效率和代码质量。