You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 02:07:01