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

React中useEffect结合useCallback后仅渲染单条API数据的问题排查

排查React组件数据渲染异常(仅显示第一条数据)的原因

问题背景

为修复useEffect的「缺少依赖项」错误引入useCallback后,出现新问题:接口返回10条数据,但页面仅渲染第一条。

问题代码

const InStream = () => {
  const [gallery, setGallery] = useState([]);
  const [loading, setLoading] = useState(false);
  let [color] = useState("#1E9A4B"); 

  const getAPI = useCallback(() => {
    fetch(url)
      .then((res) => res.json())
      .then((res) => {
        let keys = res.values[0];
        let newData = res.values.slice(1, res.values.length);

        let formatted = [],
          data = newData,
          cols = keys,
          l = cols.length;

        for (var i = 0; i < data.length; i++) {
          var d = data[i],
            o = {};
          for (var j = 0; j < l; j++) o[cols[j]] = d[j];
          formatted.push(o);
          setGallery(formatted);
          setLoading(true);
        }
      })
      .catch((error) => {
        console.error("Error:", error);
        setTimeout(() => {
          getAPI();
        }, 1000);
      });
  }, []);

  useEffect(() => {
    getAPI();
  }, [getAPI]);
  return (// my code rendering gallery data // )
};
export default InStream;

核心问题分析

  • 循环内频繁调用setState且复用数组引用:
    代码在for循环的每一次迭代中都调用setGallery(formatted),但formatted是同一个数组引用(循环外初始化的空数组,后续仅做push操作)。React的状态更新会比较前后状态的引用,当引用相同时,会判定状态未发生变化,从而不会触发组件重新渲染。只有第一次调用setGallery时,数组内容从空变为包含第一条数据,会触发渲染;后续迭代中数组内容虽增加,但引用未变,无法触发更新,最终页面仅显示第一条数据。
  • useCallback依赖项缺失:
    useCallback的依赖数组为空,导致内部的setGallery、setLoading、url都捕获了组件初始渲染时的闭包值,可能引发后续状态更新的异常。
  • var声明的变量作用域问题:
    使用var声明循环变量i、j等,会产生变量提升和函数级作用域问题,容易导致闭包逻辑错误。

修复方案

  1. 统一在循环结束后更新状态
    等所有数据处理完成,得到完整的formatted数组后,再一次性调用setGallery和setLoading,避免频繁触发渲染且解决引用问题。

  2. 补全useCallback的依赖项
    将url、setGallery、setLoading添加到useCallback的依赖数组中,确保闭包能捕获最新的状态更新函数和变量。

  3. 替换var为let/const
    把循环变量和临时变量的声明从var改为let/const,避免作用域问题。

修复后的代码示例

const InStream = () => {
  const [gallery, setGallery] = useState([]);
  const [loading, setLoading] = useState(false);
  const [color] = useState("#1E9A4B"); 

  const getAPI = useCallback(() => {
    fetch(url)
      .then((res) => res.json())
      .then((res) => {
        const keys = res.values[0];
        const newData = res.values.slice(1);
        const formatted = [];
        const cols = keys;
        const l = cols.length;

        for (let i = 0; i < newData.length; i++) {
          const d = newData[i];
          const o = {};
          for (let j = 0; j < l; j++) {
            o[cols[j]] = d[j];
          }
          formatted.push(o);
        }
        // 循环结束后统一更新状态
        setGallery(formatted);
        setLoading(true);
      })
      .catch((error) => {
        console.error("Error:", error);
        setTimeout(() => {
          getAPI();
        }, 1000);
      });
  }, [url, setGallery, setLoading]); 

  useEffect(() => {
    getAPI();
  }, [getAPI]);

  return (// 渲染gallery的代码 // )
};
export default InStream;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 08:30:49