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

React组件无限循环问题求助:无限滚动功能异常

问题原因分析
  • 渲染阶段触发状态更新导致无限循环:你在组件渲染逻辑里直接调用run_loop,而run_loop内部执行setCurrData——状态更新会触发组件重新渲染,渲染时又会因为data.length为真再次调用run_loop,形成无限循环。
  • 普通变量无法持久化状态:let i = 1是组件函数内的普通变量,每次组件重新渲染都会被重新初始化为1,导致每次run_loop都会从头取1-12条数据,重复添加到currData中。
  • 错误使用await处理非异步操作:setData和arr.concat都不是异步Promise操作,用await包裹它们没有意义,属于冗余写法。
解决方法

1. 用状态跟踪起始索引,替代普通变量

把i改成React状态,确保组件重新渲染时索引值能被保留:

const [startIndex, setStartIndex] = useState(1); // 若data数组从0开始,初始值改为0

2. 将数据处理逻辑移到useEffect中

避免在渲染阶段直接调用状态更新,改用useEffect监听data的变化,仅当data加载完成时执行一次初始化逻辑:

useEffect(() => {
  if (data.length === 0) return;

  const loadInitialData = () => {
    const arr = [];
    // 计算结束索引,避免数组越界
    const endIndex = Math.min(startIndex + 11, data.length - 1);
    for (let counter = startIndex; counter <= endIndex; counter++) {
      arr.push(
        <Pretty 
          count={counter} 
          question={data[counter].question} 
          answer_option={data[counter].option_arr} 
          answer={data[counter].answer} 
          key={data[counter]._id} 
          corr_ans={data[counter]._id}
        />
      );
    }
    setCurrData(arr);
    // 更新起始索引,为后续无限滚动预留逻辑
    setStartIndex(endIndex + 1);
  };

  loadInitialData();
}, [data]);

3. 移除渲染阶段的run_loop调用

删掉这段触发无限循环的代码:

if(data.length){
    run_loop()
}

完整修改后的代码

function QuestionAns(){
    const url = 'http://127.0.0.1:8000/'
    const [data, setData] = useState([]);
    const [currData, setCurrData] = useState([]);
    const [startIndex, setStartIndex] = useState(1); // 若data从0开始,改为0

    useEffect(() => {
        const fetchFromUrl = async() => {
            const response = await axios.get(url);
            const response_data = response.data.data; // 无需await,response.data是同步数据
            setData(response_data);
        }

        fetchFromUrl();
    }, []);

    useEffect(() => {
        if (data.length === 0) return;
        
        const loadData = () => {
            const arr = [];
            const endIndex = Math.min(startIndex + 11, data.length - 1);
            for (let counter = startIndex; counter <= endIndex; counter++) {
                arr.push(
                    <Pretty 
                        count={counter} 
                        question={data[counter].question} 
                        answer_option={data[counter].option_arr} 
                        answer={data[counter].answer} 
                        key={data[counter]._id} 
                        corr_ans={data[counter]._id}
                    />
                );
            }
            // 无限滚动扩展:若要加载更多,将setCurrData改为prev => [...prev, ...arr]
            setCurrData(arr);
            setStartIndex(endIndex + 1);
        };

        loadData();
    }, [data, startIndex]);

    return (
        <div className="container my-3">
            <div className="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-5">
                {data.length ? currData : 'loading'}
            </div>
        </div>
    )
}

export default QuestionAns;

额外提示

  • 数组索引校验:如果API返回的data是从索引0开始的常规数组,记得把startIndex初始值改为0,同时调整循环条件避免越界。
  • 无限滚动扩展:后续要实现滚动加载更多,只需监听滚动事件,当滚动到底部且startIndex < data.length时,触发数据加载逻辑即可,此时useEffect的依赖需保留startIndex,保证索引更新时能加载新数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 23:40:32