React 19中调用Fetch执行Job增删操作后页面自动刷新的问题求助
React 19中调用Fetch执行Job增删操作后页面自动刷新的问题求助
大家好,我正在跟着教程做React Web应用,目前用的是React 19和Tailwind 4.0(2025年3月8日刚搭建的项目),之前Tailwind的小问题都解决了,现在已经实现了添加和删除Job的功能,但加上react-toastify之后发现了一个奇怪的问题:
当执行删除或添加Job的操作时,整个页面会自动刷新(能看到favicon在加载),控制台也出现了错误。但只要把addJob和deleteJob里的fetch请求代码注释掉,功能就完全正常——toast提示能正常显示,页面导航也没问题,不会触发刷新。
触发问题的代码片段
注释掉以下代码后,页面就不会再自动刷新:
deleteJob中的请求代码:
const res = await fetch(`/api/jobs/${id}`, { method: "DELETE", });
addJob中的请求代码:
const res = await fetch("/api/jobs", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(newJob), });
完整代码
App.jsx
import React from "react"; import { Route, createBrowserRouter, createRoutesFromElements, RouterProvider, } from "react-router-dom"; import HomePage from "./pages/HomePage"; import MainLayout from "./layouts/MainLayout"; import JobsPage from "./pages/JobsPage"; import NotFoundPage from "./pages/NotFoundPage"; import JobPage, { jobLoader } from "./pages/JobPage"; import AddJobPage from "./pages/AddJobPage"; const App = () => { // Add new Job const addJob = async (newJob) => { const res = await fetch("/api/jobs", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(newJob), }); return; }; // Delete Job const deleteJob = async (id) => { const res = await fetch(`/api/jobs/${id}`, { method: "DELETE", }); return; }; const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<MainLayout />}> <Route index element={<HomePage />} /> <Route path="/jobs" element={<JobsPage />} /> <Route path="/add-job" element={<AddJobPage addJobSubmit={addJob} />} /> <Route path="/jobs/:id" element={<JobPage deleteJob={ deleteJob } />} loader={jobLoader} /> <Route path="*" element={<NotFoundPage />} /> </Route> ) ); return <RouterProvider router={router} />; }; export default App;
JobPage.jsx
import React from "react"; import { useParams, useLoaderData, useNavigate } from "react-router-dom"; import { FaArrowLeft, FaMapMarker } from "react-icons/fa"; import { Link } from "react-router-dom"; import { toast } from "react-toastify"; const JobPage = ({ deleteJob }) => { const navigate = useNavigate(); const { id } = useParams(); const job = useLoaderData(); const onDeleteClick = (jobId) => { const confirm = window.confirm("Are you sure want to delete this job?"); if (!confirm) return; deleteJob(jobId); toast.success("Job deleted!"); navigate("/jobs"); }; return ( <> <section> <div className="container m-auto py-6 px-6"> <Link to="/jobs" className="text-indigo-500 hover:text-indigo-600 flex items-center" > <FaArrowLeft className="mr-2" /> Back to Job Listings </Link> </div> </section> <section className="bg-indigo-50"> <div className="container m-auto py-10 px-6"> <div className="grid grid-cols-1 md:grid-cols-[70%_30%] w-full gap-6"> <main> <div className="bg-white p-6 rounded-lg shadow-md text-center md:text-left"> <div className="text-gray-500 mb-4">{job.type}</div> <h1 className="text-3xl font-bold mb-4">{job.title}</h1> <div className="text-gray-500 mb-4 flex align-middle justify-center md:justify-start"> <FaMapMarker className="mr-1 text-orange-700" /> <p className="text-orange-700">{job.location}</p> </div> </div> <div className="bg-white p-6 rounded-lg shadow-md mt-6"> <h3 className="text-indigo-800 text-lg font-bold mb-6"> Job Description </h3> <p className="mb-4">{job.description}</p> <h3 className="text-indigo-800 text-lg font-bold mb-2"> Salary </h3> <p className="mb-4">{job.salary} / Year</p> </div> </main> {/* Sidebar */} <aside> {/* Company Info */} <div className="bg-white p-6 rounded-lg shadow-md"> <h3 className="text-xl font-bold mb-6">Company Info</h3> <h2 className="text-2xl">{job.company.name}</h2> <p className="my-2">{job.company.description}</p> <hr className="my-4" /> <h3 className="text-xl">Contact Email:</h3> <p className="my-2 bg-indigo-100 p-2 font-bold"> {job.company.contactEmail} </p> <h3 className="text-xl">Contact Phone:</h3> <p className="my-2 bg-indigo-100 p-2 font-bold"> {job.company.contactPhone} </p> </div> {/* Manage */} <div className="bg-white p-6 rounded-lg shadow-md mt-6"> <h3 className="text-xl font-bold mb-6">Manage Job</h3> <Link to={`/jobs/edit/${id}`} className="bg-indigo-500 hover:bg-indigo-600 text-white text-center font-bold py-2 px-4 rounded-full w-full focus:outline-none focus:shadow-outline mt-4 block" > Edit Job </Link> <button onClick={() => onDeleteClick(job.id)} className="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-full w-full focus:outline-none focus:shadow-outline mt-4 block" > Delete Job </button> </div> </aside> </div> </div> </section> </> ); }; const jobLoader = async ({ params }) => { const res = await fetch(`/api/jobs/${params.id}`); const data = await res.json(); return data; }; export { JobPage as default, jobLoader };
预期与实际结果
我期望点击删除按钮后,页面跳转到/jobs,同时右上角显示toast.success("Job deleted!")的提示,但实际情况是页面直接刷新,toast根本来不及显示,而且控制台有错误提示。
我已经花了3个多小时搜索解决方案,甚至问了ChatGPT,但它一直说问题出在表单上,可我这删除操作是按钮触发的,根本没有表单啊... 有没有大佬能帮我看看问题出在哪?
备注:内容来源于stack exchange,提问作者Bassie
相关产品推荐
相关产品推荐

