5月30日 00:37

In real projects, how to organize and manage React Query queries, and what are the best practices for project structure and naming conventions?

In real projects, properly organizing and managing React Query queries is crucial for code maintainability and scalability:

Project Structure Organization

  1. Separate Query Functions

    • Separate data fetching logic from components
    • Create dedicated API or service layer
    • Example structure:
      shell
      src/ ├── api/ │ ├── index.js │ ├── users.js │ └── posts.js ├── components/ └── pages/
  2. Custom Hook Encapsulation

    • Create custom hooks to encapsulate common query logic
    • Provide unified interfaces and configurations
    • Example:
      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, }); };
  3. Query Key Management

    • Create centralized query key constants or utility functions
    • Ensure consistency and maintainability of query keys
    • Example:
      javascript
      // src/utils/queryKeys.js export const queryKeys = { users: 'users', user: (id) => ['user', id], posts: 'posts', userPosts: (userId) => ['posts', 'user', userId], };

Naming Conventions

  1. Query Key Naming

    • Use descriptive names
    • For dynamic parameters, use array format
    • Follow consistent naming patterns (e.g., [resource, id, action])
  2. Custom Hook Naming

    • Use use prefix
    • Names should reflect the purpose of the query
    • Examples: useUsers, useUserPosts, useCreateUser
  3. API Function Naming

    • Use clear verb+noun structure
    • Examples: fetchUsers, createUser, updatePost

Best Practices

  1. Global Configuration

    • Configure QueryClient at application entry
    • Set reasonable default options
    • Example:
      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}> {/* Application components */} </QueryClientProvider> ); }
  2. Query Grouping and Hierarchy

    • Use hierarchical query keys
    • Facilitate batch operations and invalidation
    • Example:
      javascript
      // Hierarchical query keys const userQueryKey = ['users', userId]; const userPostsQueryKey = ['users', userId, 'posts']; // Batch invalidation queryClient.invalidateQueries(['users', userId]);
  3. Code Splitting and Lazy Loading

    • For large applications, consider code splitting
    • Load query logic on demand
  4. Testing Strategy

    • Mock QueryClient and query responses
    • Test component behavior in different query states
    • Example:
      javascript
      // Using 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, }, }, }); // Pre-populate cache queryClient.setQueryData('todos', [{ id: 1, title: 'Test Todo' }]); render( <QueryClientProvider client={queryClient}> <TodoList /> </QueryClientProvider> ); expect(await screen.findByText('Test Todo')).toBeInTheDocument(); });
  5. Documentation and Comments

    • Add comments for complex queries
    • Document query purposes, cache strategies, and dependencies

By following these best practices, you can create a more structured, maintainable, and scalable React Query codebase, improving development efficiency and code quality.

标签:React