在上一篇文章《使用自訂 Hooks 簡化 React 中的 HTTP 請求? 》中,我們探討如何使用自訂 Hooks 簡化 HTTP 請求。雖然對於較小的應用程式有效,但隨著 React 應用程式的擴展,這種方法可能會變得更難以維護。在本文中,我們將深入探討如何使用 Axios 和 React Query 以可擴展的方式處理 CRUD(建立、讀取、更新、刪除)操作。
Axios:適用於瀏覽器和 Node.js 的基於 Promise 的 HTTP 用戶端,Axios 使用乾淨、可讀的程式碼簡化了向 REST 端點發送非同步 HTTP 請求的過程。
React Query:一個強大的資料擷取庫,可增強 React 中的資料同步、快取和狀態管理。 React Query 可自動取得數據,同時提供對載入和錯誤狀態的更好控制。
首先,安裝必要的軟體包:
npm install axios react-query react-router-dom
接下來,在入口檔案 (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 實例並使用攔截器為經過驗證的請求附加 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 };
讓我們定義與 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}`);
現在我們有了 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 }); };
最後,我們可以建立一個簡單的元件,它使用自訂掛鉤並允許使用者建立、編輯和刪除貼文。
// 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中文網其他相關文章!