本文详解如何使用 useeffect 配合空依赖数组,确保 react 函数组件中的初始化 api 请求仅执行一次,防止因状态更新导致的无限重渲染与请求爆炸问题。
本文详解如何使用 useeffect 配合空依赖数组,确保 react 函数组件中的初始化 api 请求仅执行一次,防止因状态更新导致的无限重渲染与请求爆炸问题。
在 React 函数组件中,直接在组件顶层(render body)发起网络请求是严重错误实践——每次状态更新(如 setProgress)都会触发组件重新执行,从而反复调用 axios.get,形成恶性循环,最终耗尽浏览器资源甚至导致崩溃。
你原代码的问题核心在于:
- axios.get(...).then(...) 被写在组件函数体内部,而非副作用管理机制中;
- 循环中频繁调用 setProgress(progress + 1) 触发多次重渲染,每次重渲染都重新执行整个 App 函数,包括初始请求;
- 缺乏依赖控制,无法保证副作用“只运行一次”。
✅ 正确解法:使用 useEffect 并传入空依赖数组 [],将其声明为“仅在组件挂载时执行一次”的副作用:
使用 @ainative/react-sdk 为 React 应用添加 AI 聊天和积分。适用于 (1) 安装 @ainative/react-sdk,(2) 使用 useChat hook 实现聊天完成。
import './App.css';
import axios from 'axios';
import React, { useState, useEffect } from 'react';
function App() {
const [allDataJson, setAllData] = useState(null);
const [progress, setProgress] = useState(0);
useEffect(() => {
// ✅ 此逻辑仅在组件首次挂载时执行一次
const fetchAllPokemon = async () => {
try {
// 第一步:获取全部 Pokémon 列表(分页拉取)
let allResults = [];
let url = "https://pokeapi.co/api/v2/pokemon/?offset=0&limit=20";
while (url) {
const response = await axios.get(url);
allResults = [...allResults, ...response.data.results];
url = response.data.next; // 自动处理分页,避免 do-while + await 混用风险
}
// 第二步:并发获取详情(推荐 Promise.all 提升性能)
const detailPromises = allResults.map(async (item) => ({
...item,
detail: await getDetails(item.url)
}));
// 使用 Promise.all 并行加载,避免串行阻塞 + 多次 setState
const fullData = await Promise.all(detailPromises);
setAllData(fullData); // ✅ 一次性设置最终数据
} catch (error) {
console.error("Failed to load Pokémon data:", error);
}
};
fetchAllPokemon();
}, []); // ? 空数组 = 无依赖,仅挂载时执行
return (
<div>
{allDataJson ? (
<div>
<h2>✅ 加载完成!共 {allDataJson.length} 只宝可梦</h2>
<pre class="brush:php;toolbar:false;">{JSON.stringify(allDataJson.slice(0, 2), null, 2)}










