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
相关产品推荐
相关产品推荐

