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

React中GraphQL+Axios添加数据后useEffect重取致应用崩溃

看起来你碰到的是请求配置、超时处理和逻辑漏洞叠加导致的问题,我之前也遇到过类似的情况,咱们一步步来排查和解决:

核心问题拆解

初始加载能正常获取数据,但添加事件后的二次请求超时失败,本质上是三个问题:请求权限不匹配、Axios无超时配置导致长时间阻塞、错误处理不完整引发应用崩溃,再加上useEffect里的异步状态逻辑有漏洞。

1. 先补全请求头的权限信息

你会发现fetchEvents的请求只带了Content-Type头,但handleConfirm里的mutation请求带了Authorization头。很大概率是你的后端在创建事件后,后续的查询请求也要求身份认证了——初始加载可能允许匿名访问,但添加事件后服务器的权限校验逻辑触发,不带token的查询请求被后端挂起(而不是直接拒绝),最终导致超时。

解决办法:把认证token也加到fetchEvents的请求头里:

const headers = {
  'Content-Type': 'application/json',
  // 只有存在token时才添加认证头,兼容初始匿名加载的情况
  ...(authContext.token && { 'Authorization': `Bearer ${authContext.token}` })
}

2. 给Axios设置合理超时时间

Axios默认的超时时间是0(也就是永不超时),这就是为什么你要等2分钟才触发catch的原因。这种长时间的请求阻塞会让应用处于假死状态,最终可能因为资源耗尽崩溃。

解决办法:在所有Axios请求里加上timeout配置,比如设置10秒超时:

axios.post('http://localhost:5000/graphql', body, {
  headers,
  timeout: 10000 // 10秒后自动终止请求
})

3. 修复useEffect里的异步状态逻辑漏洞

你当前的useEffect里,setAdded(false)和setInitialFetch(false)都是异步操作,直接在后面调用fetchEvents会导致状态更新和请求执行的顺序不可控,而且没有加载状态的管理,容易出现重复请求或者用户无感知的情况。

优化后的useEffect代码:

const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);

useEffect(() => {
  const fetchEvents = async () => {
    setIsLoading(true);
    setError(null); // 每次请求前清空错误状态
    try {
      const headers = {
        'Content-Type': 'application/json',
        ...(authContext.token && { 'Authorization': `Bearer ${authContext.token}` })
      };
      const requestBody = {
        query: `
          query {
            events {
              _id title description price
            }
          }
        `
      };
      console.log('fetching events from db');
      const res = await axios.post(
        'http://localhost:5000/graphql',
        JSON.stringify(requestBody),
        { headers, timeout: 10000 }
      );
      setEvents(res.data.data.events);
    } catch (err) {
      console.error('Failed to fetch events:', err);
      setError('加载事件失败,请稍后重试'); // 设置错误状态,在UI上提示用户
    } finally {
      setIsLoading(false); // 不管成功失败都结束加载状态
    }
  };

  // 初始加载或添加事件后触发请求
  if (initialFetch || added) {
    // 重置触发状态
    if (initialFetch) setInitialFetch(false);
    if (added) setAdded(false);
    fetchEvents();
  }
}, [added, initialFetch, authContext.token]); // 把token加入依赖,确保token变化时重新请求

这里用async/await让逻辑更清晰,添加了加载状态和错误状态,还补全了依赖项,避免因依赖缺失导致的bug。

4. 完善错误处理,避免应用崩溃

现在你的catch块只是打印错误,但没有在UI层面给用户反馈,也没有处理未捕获的异常。添加错误状态后,在UI里展示错误提示:

{error && <div className="alert alert-error">{error}</div>}
{isLoading && <div>加载中...</div>}

这样用户能明确知道出了问题,应用也不会因为未处理的错误崩溃。

5. 排查后端是否存在请求阻塞

如果上面的方法都没用,那可能是后端的问题:比如创建事件后数据库锁死、GraphQL resolver逻辑卡住,或者服务器资源不足导致请求排队。可以去后端的日志里查看有没有慢查询、报错或者死锁的记录,比如检查MongoDB的查询是否添加了合适的索引,GraphQL的mutation和query resolver有没有逻辑漏洞。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 08:22:48