首页  >  文章  >  web前端  >  使用 Axios 和 React Query 响应 CRUD 操作

使用 Axios 和 React Query 响应 CRUD 操作

Patricia Arquette
Patricia Arquette原创
2024-09-24 20:30:40354浏览

React CRUD Operations with Axios and React Query

在上一篇文章《使用自定义 Hooks 简化 React 中的 HTTP 请求?》中,我们探讨了如何使用自定义 Hooks 简化 HTTP 请求。虽然对于较小的应用程序有效,但随着 React 应用程序的扩展,这种方法可能会变得更难以维护。在本文中,我们将深入探讨如何使用 Axios 和 React Query 以可扩展的方式处理 CRUD(创建、读取、更新、删除)操作。

为什么选择 Axios 和 React Query?

  • Axios:适用于浏览器和 Node.js 的基于 Promise 的 HTTP 客户端,Axios 使用干净、可读的代码简化了向 REST 端点发送异步 HTTP 请求的过程。

  • React Query:一个强大的数据获取库,可增强 React 中的数据同步、缓存和状态管理。 React Query 可自动获取数据,同时提供对加载和错误状态的更好控制。

设置 Axios 和 React 查询

首先,安装必要的软件包:

npm install axios react-query react-router-dom

在您的应用程序中设置 React 查询

接下来,在入口文件 (App.tsx) 中配置 React Query 来管理应用程序的全局查询设置。

// src/App.tsx
import { QueryClient, QueryClientProvider } from 'react-query';
import { CustomRouter } from './Router';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      refetchOnWindowFocus: false,  // Prevent refetch on tab/window switch
      retry: 1,                     // Retry failed queries once
    },
  },
});

const App: React.FC = () => (
  <QueryClientProvider client={queryClient}>
    <CustomRouter />
  </QueryClientProvider>
);

export default App;

使用拦截器设置 Axios

要处理全局身份验证,我们可以创建一个 Axios 实例并使用拦截器为经过身份验证的请求附加 Authorization 标头。

// src/config/axiosApi.ts
import axios from 'axios';

const authenticatedApi = axios.create({
  baseURL: import.meta.env.VITE_BASE_URL,  // Environment-specific base URL
  headers: {
    'Content-Type': 'application/json',
  },
});

// Attach Authorization token to requests if present
authenticatedApi.interceptors.request.use((config) => {
  const token = localStorage.getItem('crud-app-auth-token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

export { authenticatedApi };

为 CRUD 操作创建 API 函数

让我们定义与 API 交互的函数,以使用 Axios 执行 CRUD 操作:

// src/data/api/post.ts
import { authenticatedApi } from '../../config/axiosApi';

// Error handler function to standardize error messages
export const handleApiError = (error: any): never => {
  if (error.message === 'Network Error') {
    throw new Error('Network Error. Please try again later.');
  } else if (error.response?.data?.error) {
    throw new Error(error.response.data.error);
  } else if (error.response) {
    throw new Error('A server error occurred.');
  } else {
    throw new Error(error.message || 'An unknown error occurred.');
  }
};

// General function to handle API requests
export const apiCall = async <T>(
  method: 'get' | 'post' | 'put' | 'delete',
  url: string,
  data?: any,
): Promise<T> => {
  try {
    const response = await authenticatedApi[method](url, data);
    return response.data;
  } catch (error) {
    throw handleApiError(error);
  }
};

// CRUD functions for the post feed
export const createPostApi = (post: any) => apiCall<any>('post', 'posts', post);
export const getPostsApi = () => apiCall<any>('get', 'posts');
export const updatePostApi = (id: string, post: any) => apiCall<any>('put', `posts/${id}`, post);
export const deletePostApi = (id: string) => apiCall<any>('delete', `posts/${id}`);

使用 React Query Hooks 进行 CRUD 操作

现在我们有了 API 函数,我们可以使用 React Query 来处理这些操作的状态管理和数据获取。

// src/data/hooks/post.ts
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { createPostApi, getPostsApi, updatePostApi, deletePostApi } from '../api/post';

// Custom hooks for CRUD operations
export const useCreatePostApi = () => {
  const queryClient = useQueryClient();
  return useMutation(createPostApi, {
    onSuccess: () => queryClient.invalidateQueries(['posts']), // Refetch posts after a new post is created
  });
};

export const useGetPostsApi = () => useQuery(['posts'], getPostsApi);

export const useUpdatePostApi = () => {
  const queryClient = useQueryClient();
  return useMutation(updatePostApi, {
    onSuccess: () => queryClient.invalidateQueries(['posts']), // Refetch posts after an update
  });
};

export const useDeletePostApi = () => {
  const queryClient = useQueryClient();
  return useMutation(deletePostApi, {
    onSuccess: () => queryClient.invalidateQueries(['posts']), // Refetch posts after deletion
  });
};

在组件中使用 CRUD 挂钩

最后,我们可以构建一个简单的组件,它使用自定义挂钩并允许用户创建、编辑和删除帖子。

// src/components/PostCard.tsx
import React, { useState } from 'react';
import { useGetPostsApi, useDeletePostApi, useUpdatePostApi, useCreatePostApi } from '../data/hooks/post';
import { toast } from '../components/Toast';  // Assume a toast component exists

const PostCard: React.FC = () => {
  const { data: posts, isLoading, error } = useGetPostsApi();
  const deletePost = useDeletePostApi();
  const updatePost = useUpdatePostApi();
  const createPost = useCreatePostApi();
  const [newPost, setNewPost] = useState({ title: '', content: '' });

  const handleCreate = async () => {
    try {
      await createPost.mutateAsync(newPost);
      setNewPost({ title: '', content: '' });
      toast.success('Post created successfully');
    } catch (error) {
      toast.error(error.message);
    }
  };

  const handleDelete = async (id: string) => {
    try {
      await deletePost.mutateAsync(id);
      toast.success('Post deleted successfully');
    } catch (error) {
      toast.error(error.message);
    }
  };

  const handleEdit = async (id: string, updatedPost: any) => {
    try {
      await updatePost.mutateAsync({ id, ...updatedPost });
      toast.success('Post updated successfully');
    } catch (error) {
      toast.error(error.message);
    }
  };

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <div>
        <input
          type="text"
          value={newPost.title}
          onChange={(e) => setNewPost({ ...newPost, title: e.target.value })}
          placeholder="Title"
        />
        <input
          type="text"
          value={newPost.content}
          onChange={(e) => setNewPost({ ...newPost, content: e.target.value })}
          placeholder="Content"
        />
        <button onClick={handleCreate} disabled={createPost.isLoading}>
          {createPost.isLoading ? 'Creating...' : 'Create Post'}
        </button>
      </div>

      {posts?.map((post: any) => (
        <div key={post.id}>
          <h3>{post.title}</h3>
          <p>{post.content}</p>
          <button onClick={() => handleEdit(post.id, { title: 'Updated Title', content: 'Updated Content' })}>
            Edit
          </button>
          <button onClick={() => handleDelete(post.id)}>
            Delete
          </button>
        </div>
      ))}
    </div>
  );
};

export default PostCard;

结论

通过使用 Axios 和 React Query,您可以简化 React 应用程序中的 CRUD 操作。这种组合会产生干净、可维护的代码,从而提高可扩展性和性能。随着应用程序的增长,使用这些工具可以简化状态管理和数据获取。

有关 React、TypeScript 和现代 Web 开发实践的更多见解,请在 Dev.to 上关注我! ?‍?

以上是使用 Axios 和 React Query 响应 CRUD 操作的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn