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

如何解决useEffect首次渲染时同时执行两个函数无数据问题

问题分析与解决方案

你的问题核心在于闭包捕获旧状态+异步更新的竞态覆盖:

  • 由于useEffect使用空依赖数组,内部的values变量会一直保持组件首次渲染时的初始值。
  • getCategory和getPublisher是异步请求,它们完成的顺序不确定,后完成的请求执行setValues({ ...values, ... })时,会基于初始的values重新构建状态对象,直接覆盖先完成请求的更新结果(比如先完成的请求刚把categories设好,后完成的请求就用初始值覆盖,导致categories变回初始状态)。

解决方法1:使用函数式状态更新(推荐)

React的setState支持传入函数,函数会接收最新的状态值作为参数,这样就能确保每次更新都是基于当前最新的状态,不会被闭包的旧值影响:

useEffect(() => {
  const getCategory = () => {
    allcategory().then((res) => {
      if (res.data.error) {
        console.log("error");
        setValues(prev => ({ 
          ...prev,
          message: res.data.error
        }));
      } else {
        setValues(prev => ({ 
          ...prev,
          categories: res.data.category,
          formData: new FormData(),
        }));
      }
    });
  };

  const getPublisher = () => {
    allpublisher().then((res) => {
      if (res.data.error) {
        console.log("error");
        setValues(prev => ({ 
          ...prev,
          message: res.data.error
        }));
      } else {
        setValues(prev => ({ 
          ...prev,
          publishers: res.data.publisher,
          formData: new FormData(),
        }));
      }
    });
  };

  getCategory();
  getPublisher();
}, []);

解决方法2:合并异步请求,一次性更新状态

如果两个请求没有依赖关系,可以用Promise.all同时发起,等待全部请求完成后再统一更新状态,避免多次状态更新的竞态:

useEffect(() => {
  Promise.all([allcategory(), allpublisher()])
    .then(([categoryRes, publisherRes]) => {
      const newValues = { ...values };
      let hasError = false;

      if (categoryRes.data.error) {
        console.log("category error");
        newValues.message = categoryRes.data.error;
        hasError = true;
      } else {
        newValues.categories = categoryRes.data.category;
      }

      if (!hasError && publisherRes.data.error) {
        console.log("publisher error");
        newValues.message = publisherRes.data.error;
        hasError = true;
      } else if (!hasError) {
        newValues.publishers = publisherRes.data.publisher;
      }

      newValues.formData = new FormData();
      setValues(newValues);
    })
    .catch(err => {
      console.log("request error", err);
      setValues(prev => ({ ...prev, message: "请求失败" }));
    });
}, []);

额外提示:如果formData不需要每次状态更新都重新创建,可以考虑用useRef存储它,避免不必要的实例化,减少性能开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:05:19