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

React使用useEffect调用Axios接口出现无限请求或数据不渲染问题

问题根因

  • 状态更新的异步闭包陷阱:React的setState是异步批量执行的,调用setClients(response.data)后,当前作用域下的clients仍然是本次渲染的旧值(初始空数组),你直接拿这个旧值做map生成rows、打印,自然拿到的是空结果。偶现渲染成功是因为极个别情况下渲染时序变化,刚好拿到了上一次更新的状态值。
  • 函数引用变化导致死循环:组件每次渲染都会重新创建fetchClients函数,如果你把它加入useEffect依赖,每次渲染都会触发useEffect重新执行,调用接口更新状态后又触发重渲染,形成无限调用的死循环。
  • loading状态逻辑错误:你将setLoading(false)写在了请求判断逻辑之外,且请求完成后设置loading为true,和常规加载逻辑完全相反,会导致请求触发逻辑异常。

修复方案

方案1:直接将请求逻辑写在useEffect内(仅挂载时请求一次场景推荐)

不需要额外处理函数依赖,代码更简洁:

const [clients, setClients] = useState([]);
const [rows, setRows] = useState([]);
const [loading, setLoading] = useState(false);

useEffect(() => {
  // 加组件挂载标识,避免组件卸载后更新状态触发警告
  let isMounted = true;
  if (loading) return;
  setLoading(true);

  axios
    .get(API_URL_CLIENTS + "?users_permissions_user.email=" + USER_KEY_EMAIL)
    .then((response) => {
      if (!isMounted || response.status !== 200) return;
      const resData = response.data;
      setClients(resData);
      // 直接用接口返回数据生成rows,避开闭包陷阱
      const newRows = resData.map((client) => ({
        id: client.id,
        col1: client.nom,
        col2: client.prenom,
        col3: client.mail,
        col4: client.telephone,
      }));
      setRows(newRows);
    })
    .catch((error) => {
      console.log(error);
    })
    .finally(() => {
      if (isMounted) setLoading(false);
    });

  return () => {
    isMounted = false;
  };
}, []); // 依赖为空,仅挂载时执行一次

方案2:用useCallback缓存fetchClients(需要多处调用请求场景推荐)

如果需要在组件其他地方也调用fetchClients,可以用useCallback缓存函数引用避免死循环:

import { useState, useEffect, useCallback } from 'react';

const [clients, setClients] = useState([]);
const [rows, setRows] = useState([]);
const [loading, setLoading] = useState(false);

const fetchClients = useCallback(() => {
  if (loading) return;
  setLoading(true);

  axios
    .get(API_URL_CLIENTS + "?users_permissions_user.email=" + USER_KEY_EMAIL)
    .then((response) => {
      if (response.status !== 200) return;
      const resData = response.data;
      setClients(resData);
      const newRows = resData.map((client) => ({
        id: client.id,
        col1: client.nom,
        col2: client.prenom,
        col3: client.mail,
        col4: client.telephone,
      }));
      setRows(newRows);
    })
    .catch((error) => {
      console.log(error);
    })
    .finally(() => {
      setLoading(false);
    });
}, [loading]);

useEffect(() => {
  fetchClients();
}, [fetchClients]); // 加入缓存后的函数依赖,不会触发死循环

可选优化

如果没有单独修改rows的需求,你可以用useMemo直接从clients派生rows,不需要单独维护rows状态,减少冗余状态避免不同步问题:

import { useMemo } from 'react';

const rows = useMemo(() => {
  return clients.map((client) => ({
    id: client.id,
    col1: client.nom,
    col2: client.prenom,
    col3: client.mail,
    col4: client.telephone,
  }));
}, [clients]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 03:36:01