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

React中POST请求后如何用useEffect即时获取数据及方案验证

实现方案评估

你的核心实现思路(用状态变化触发useEffect重新拉取数据)是可行的,但现有代码存在几个会导致功能异常的问题,修正后即可稳定运行。

现存问题

  • 时序错误:提交表单时你先触发刷新状态、再调用添加接口,而axios请求是异步的,会导致拉取数据的请求比提交请求更早到达服务端,大概率拿到的还是提交前的旧数据,极端情况还会触发服务端报错。
  • 状态语义模糊:用布尔值send作为刷新触发标识,后续代码迭代时很难快速理解这个状态的作用,直接把setSend方法透传给业务组件也不符合状态封装原则。
  • 请求配置有误:提交普通JSON数据时强行设置了multipart/form-data请求头,这个头是用于传输文件/表单格式数据的,普通JSON请求用axios默认的application/json即可,错误配置头可能导致后端解析参数失败。
  • 缺少交互兜底:没有提交加载状态、错误提示,用户重复点击提交会发送多次重复请求,提交失败时用户也无法感知。

修正后的代码

1. Context 状态逻辑调整

把布尔触发值改成语义更清晰的递增计数标识,封装刷新方法不直接暴露setState,调整请求触发时机:

import { createContext, useState, useEffect } from "react";
import { apiService } from "../services/api/api.service";

const Context = createContext({
  footer: false,
  subjectForm: false,
  storedSubjects: [],
  footerVisibilityHandler: () => {},
  subjectFormVisibilityHandler: () => {},
  refreshSubjects: () => {},
});

export const ContextProvider = ({ children }) => {
  const [footer, setFooter] = useState(false);
  const [subjectForm, setSubjectForm] = useState(false);
  const [storedSubjects, setStoredSubjects] = useState([]);
  // 用递增数字作为刷新触发key,语义更清晰
  const [refreshKey, setRefreshKey] = useState(0);

  useEffect(() => {
    const getData = async () => {
      try {
        const getSubjects = await apiService.getSubjects();
        const tableRow = getSubjects.data.map((subject) => ({
          name: subject.name,
        }));
        setStoredSubjects(tableRow);
      } catch (err) {
        console.error("拉取科目列表失败:", err);
        // 可在此处添加全局错误提示
      }
    };
    getData();
  }, [refreshKey]);

  const footerVisibilityHandler = () => {
    setFooter((previousState) => !previousState);
    setSubjectForm(false);
  };

  const subjectFormVisibilityHandler = () => {
    setSubjectForm((previousState) => !previousState);
  };

  const context = {
    footer,
    subjectForm,
    storedSubjects,
    footerVisibilityHandler,
    subjectFormVisibilityHandler,
    // 封装刷新方法,不直接暴露setState
    refreshSubjects: () => setRefreshKey(prev => prev + 1),
  };

  return <Context.Provider value={context}>{children}</Context.Provider>;
};

export default Context;

2. 表单组件提交逻辑调整

等添加接口请求成功后再触发列表刷新,加提交loading状态防止重复提交:

import Context from "../../store/context";
import FormContainer from "../UI/FormContainer";
import { apiService } from "../../services/api/api.service";
import { useContext, useRef, useState } from "react";

const AddSubject = () => {
  const ctx = useContext(Context);
  const subject = useRef("");
  const [submitting, setSubmitting] = useState(false);

  const sendData = async (e) => {
    e.preventDefault();
    const subjectName = subject.current.value.trim();
    if (!subjectName) return;
    setSubmitting(true);
    try {
      // 等待提交成功后再刷新列表
      await apiService.addSubject(subjectName);
      ctx.refreshSubjects();
      // 提交成功后清空输入框、关闭表单
      subject.current.value = "";
      ctx.subjectFormVisibilityHandler();
    } catch (err) {
      console.error("添加科目失败:", err);
      // 可在此处添加用户可见的错误提示
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <FormContainer show={ctx.subjectForm} send={sendData}>
      <label htmlFor="subject">Subject Name: </label>
      <input type="text" id="subject" ref={subject} disabled={submitting} />
      <button type="submit" disabled={submitting}>
        {submitting ? "提交中..." : "Add"}
      </button>
    </FormContainer>
  );
};

export default AddSubject;

3. API 配置调整

删除不必要的请求头配置:

import axios from "axios";

const api = () => {
  const baseUrl = "https://localhost:5001/api";
  // 普通JSON请求不需要自定义请求头,axios默认配置即可满足
  return {
    getSubjects: () => axios.get(`${baseUrl}/subjectcontroller/getsubjects`),
    addSubject: (subjectName) =>
      axios.post(`${baseUrl}/subjectcontroller/createsubject`, {
        name: subjectName,
      }),
  };
};

export const apiService = api();

额外优化建议

如果后续项目里同类数据刷新场景变多,可以把数据拉取、loading、错误处理都封装成通用的自定义hook,不用每个列表都单独写一套刷新触发状态,维护成本会低很多。

内容的提问来源于stack exchange,提问作者Adrian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 01:45:35