如何在React中实现无需刷新页面更新员工门户表单条目列表?
我开发的系统包含一个可填写的表单,表单提交后,填写的信息会展示在员工门户中,但目前新提交的条目必须刷新网站才能显示。以下是我的useReducer代码、表单处理函数代码以及表单列表展示代码,请问如何实现无需刷新页面即可更新条目列表?
useReducer代码
import { createContext, useReducer } from "react"; export const FireInsuranceContext = createContext(); export const FireInsuranceReducer = (state, action) => { switch (action.type) { case "SET_FIREINSURANCES": return { fireInsurances: action.payload, }; case "CREATE_FIREINSURANCE": return { fireInsurances: [action.payload, ...state.fireInsurances], }; case "DELETE_FIREINSURANCE": return { fireInsurances: state.fireInsurances.filter( (f) => f._id !== action.payload._id ), }; case "RESOLVE_FIREINSURANCE": return { fireInsurances: state.fireInsurances.map((fire) => fire._id === action.payload._id ? { ...fire, resolved: action.payload.resolved } : fire ), }; default: return state; } }; export const FireInsuranceContextProvider = ({ children }) => { const [state, dispatch] = useReducer(FireInsuranceReducer, { fireInsurances: [], }); return ( <FireInsuranceContext.Provider value={{ ...state, dispatch }}> {children} </FireInsuranceContext.Provider> ); };
表单处理函数代码
const formHandler = async (e) => { //other stuff try { const response = await fetch("http://localhost:2213/api/fire-emailer", { mode: "cors", method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(requestBody), }); const json = await response.json(); if (!response.ok) { setError(json.error); setLoading(false); console.log(json.error); } if(response.ok) { dispatch({ type: "CREATE_FIREINSURANCE", payload: json }); console.log("workoutadded", json) setNotif(true); setLoading(false); setError(""); setName(""); setAddress(""); setContact(""); setEmail(""); setCompany(""); setInfrastructure(""); setConstruction(""); } console.log(json); } catch (error) { console.log(error); setError("An error occurred. Please try again later."); setLoading(false); } }
表单列表展示代码
const FireInsuranceList = () => { const { fireInsurances, dispatch } = useContext(FireInsuranceContext); useEffect(() => { const fetchFireInsurance = async () => { const response = await fetch( "http://localhost:2213/api/getInsurance/fire-insurance", { mode: "cors", headers: { "Content-Type": "application/json", }, } ); const json = await response.json(); if (response.ok) { dispatch({ type: "SET_FIREINSURANCES", payload: json }); console.log("useEffect ran") } }; fetchFireInsurance(); },[dispatch]); return ( <div className="px-2 mt-3"> <div className="flex justify-between flex-wrap"> <div className="flex gap-x-2"> <form className="relative"> <input className="border border-gray-800 rounded-md text-sm p-1" placeholder="Search Name" type="search" /> <button className="absolute top-1/2 -translate-y-1/2 right-1"> <FontAwesomeIcon icon={faMagnifyingGlass} /> </button> </form> <select className="text-sm p-1 rounded-md border-gray-800 border bg-white"> <option value="all">All</option> <option value="solved">Solved</option> <option value="unresolved">Unresolved</option> </select> </div> <h3 className="font-bold">Fire Insurance Inquiries</h3> </div> <div> {fireInsurances.length !== 0 ? ( <div className="flex flex-wrap justify-around gap-3 my-10"> {fireInsurances.map((fireInsurance) => ( <FireInsuranceDetails key={fireInsurance._id} fireInsurance={fireInsurance} /> ))} </div> ) : ( <div className="text-center text-xl font-bold mt-10 text-gray-700"> No Fire Insurance Inquiries </div> )} </div> </div> ); }; export default FireInsuranceList;
解决方案
你的代码已经具备无刷新更新的基础,只需确认以下几个关键点:
1. 确认上下文作用域范围
表单组件和FireInsuranceList必须都被包裹在FireInsuranceContextProvider内部,这样两者才能共享同一状态。如果组件不在同一个上下文里,dispatch更新状态后列表组件无法感知变化。
2. 验证状态更新逻辑
Reducer里的CREATE_FIREINSURANCE已经正确把新条目添加到数组开头,要确保后端返回的json数据结构和现有条目一致,尤其是必须包含唯一的_id字段,避免渲染时key冲突。
3. 检查dispatch是否正确触发
表单提交成功后,确认dispatch({ type: "CREATE_FIREINSURANCE", payload: json })确实被执行:
- 打开控制台看是否有
workoutadded的日志 - 确认后端返回的
response.ok为true,没有进入错误分支
4. 避免重复拉取数据
FireInsuranceList的useEffect只在挂载时拉取一次数据是正确的,后续状态更新靠dispatch直接修改上下文,不需要重新请求接口,否则会覆盖手动添加的新条目。
5. 确认列表监听状态变化
FireInsuranceList通过useContext获取fireInsurances,状态更新时组件会自动重渲染。如果没更新,检查:
- 是否正确使用
useContext(FireInsuranceContext)获取状态 - 列表渲染是否用了唯一的
key(你已经用_id,没问题)
如果以上都没问题,系统应该就能实现无刷新更新列表。还可以在控制台打印fireInsurances,确认dispatch执行后状态是否变化。
内容的提问来源于stack exchange,提问作者Matthew Jalowe Macaranas

