React Router v6+:如何用useLoaderData实现无刷新删除数据
解决react-router-dom@6删除数据后无刷新更新页面问题
问题根源
你当前代码中,products()只是返回useLoaderData()的结果,但useLoaderData()仅在组件挂载或路由首次匹配时加载数据,手动调用该函数无法触发loader重新获取最新数据,因此删除后页面数据不会自动更新。
解决方案1:使用useRevalidator手动触发loader更新
这种方法无需修改路由配置,只需在组件内添加useRevalidator hook,在删除成功后触发数据重新加载。
修改后的Product组件代码:
import { useLoaderData, useRevalidator } from "react-router-dom"; import axiosClient from "../../../axios-client" export const ProductData = () => { return axiosClient.get('admin/product') .then(({ data }) => data.data) .catch((error) => error) } export default function Product() { // 直接赋值useLoaderData的结果,无需封装成函数 const products = useLoaderData(); const { revalidate } = useRevalidator(); const ProductDelete = async(id) => { try { await axiosClient.delete(`admin/product/delete/${id}`); // 删除成功后触发loader重新获取数据 await revalidate(); } catch (error) { console.error("删除失败:", error); } } return ( <div className="flex flex-col"> <table className="min-w-full divide-y divide-gray-500"> <thead className="bg-red-500"> <tr> <th>id</th> </tr> </thead> <tbody className="divide-y divide-gray-200"> {products && products.map((product) => ( <tr key={product.id}> <td className="px-6 py-4 text-sm font-medium text-gray-800 whitespace-nowrap"> <button onClick={()=>ProductDelete(product.id)}>Delete</button> </td> </tr> ))} </tbody> </table> </div> ); }
解决方案2:使用路由action + Form组件(推荐)
这是react-router-dom@6.4+推荐的最佳实践,将删除逻辑放到路由的action中,通过Form组件提交请求,完成后自动触发loader重新加载数据。
步骤1:修改组件,添加action函数并使用Form组件
import { useLoaderData, Form } from "react-router-dom"; import axiosClient from "../../../axios-client" export const ProductData = () => { return axiosClient.get('admin/product') .then(({ data }) => data.data) .catch((error) => error) } // 定义删除的action函数 export const ProductDeleteAction = async ({ request }) => { const formData = await request.formData(); const id = formData.get('id'); try { await axiosClient.delete(`admin/product/delete/${id}`); return { success: true }; } catch (error) { return { error: error.message }; } } export default function Product() { const products = useLoaderData(); return ( <div className="flex flex-col"> <table className="min-w-full divide-y divide-gray-500"> <thead className="bg-red-500"> <tr> <th>id</th> </tr> </thead> <tbody className="divide-y divide-gray-200"> {products && products.map((product) => ( <tr key={product.id}> <td className="px-6 py-4 text-sm font-medium text-gray-800 whitespace-nowrap"> {/* 使用react-router的Form组件提交删除请求 */} <Form method="POST"> <input type="hidden" name="id" value={product.id} /> <button type="submit">Delete</button> </Form> </td> </tr> ))} </tbody> </table> </div> ); }
步骤2:更新路由配置,添加action
import Product, { ProductData, ProductDeleteAction } from "./components/admin/product/IndexProduct" const router = createBrowserRouter([ { path: "product", element: <Product />, loader: ProductData, action: ProductDeleteAction // 绑定action } ]);
两种方案说明
- 方案1适合快速修改,代码改动小;
- 方案2符合react-router的设计理念,将数据操作逻辑与组件解耦,更利于维护和扩展。
内容的提问来源于stack exchange,提问作者Ray Paras
相关产品推荐
相关产品推荐

