React中API重复请求及元素识别问题求助
问题解决:API重复请求与多次日志输出优化
问题分析
- API重复请求:你的
useEffect依赖数组为空,理论上仅在组件挂载时执行一次,但开发环境下React Strict Mode会强制双调用useEffect(用于检测副作用),这是预期行为;若生产环境仍有重复请求,需检查组件是否被重复挂载(如路由配置、父组件重渲染导致卸载再挂载)。 - 多次日志输出:组件每次重渲染(
setData/setLoading/setError触发时)都会执行函数体代码,包括价格计算和console.log,因此会多次打印;初始data为null,所以第一次输出undefined。 - 请求限制:重复请求(尤其是开发环境双调用+组件重复挂载)会导致短时间内请求次数超限。
解决方案
1. 给请求添加取消控制器,避免无效请求
给fetch加上AbortController,组件卸载时取消未完成的请求,同时忽略取消操作的错误:
import { useState, useEffect, useMemo } from "react"; function App() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const controller = new AbortController(); const signal = controller.signal; fetch("http://localhost:4500/coingeckotest", { signal }) .then(response => { if (response.ok) { return response.json(); } throw response; }) .then(fetchedData => { setData(fetchedData); }) .catch(error => { // 忽略取消请求的错误 if (error.name !== "AbortError") { console.error("Error fetching data: ", error); setError(error); } }) .finally(() => { setLoading(false); }); // 组件卸载时取消请求 return () => controller.abort(); }, []);
2. 用useMemo缓存价格计算结果,避免重复执行find
每次重渲染时find操作会重复执行,用useMemo缓存计算结果,仅在data变化时重新计算:
const { uniprice, sushiprice, curveprice, quickprice } = useMemo(() => { if (!data) { return { uniprice: undefined, sushiprice: undefined, curveprice: undefined, quickprice: undefined }; } const uniswap = data[0].tickers?.find(donne => donne.trade_url === "https://app.uniswap.org/#/swap?inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c599&outputCurrency=ETH" ); const sushiswap = data[1].tickers?.find(donne => donne.trade_url === "https://app.sushi.com/swap?inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c599&outputCurrency=ETH" ); const curvefinance = data[2].tickers?.find(donne => donne.base === "DAI"); const quickswap = data[3].tickers?.find(donne => donne.trade_url === "https://quickswap.exchange/#/swap?inputCurrency=0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270&outputCurrency=0xbbba073c31bf03b8acf7c28ef0738decf3695683" ); return { uniprice: uniswap?.converted_last?.usd, sushiprice: sushiswap?.converted_last?.usd, curveprice: curvefinance?.converted_last?.usd, quickprice: quickswap?.converted_last?.usd }; }, [data]);
3. 仅在数据更新时打印日志
把console.log放到监听data变化的useEffect里,避免每次重渲染都打印:
useEffect(() => { if (data) { console.log(uniprice, sushiprice, curveprice, quickprice); } }, [data, uniprice, sushiprice, curveprice, quickprice]); if (loading) return "Loading..."; if (error) return "Error !"; return ( <> {/* 在这里渲染价格数据,比如: */} <div>Uniswap Price: {uniprice}</div> <div>Sushiswap Price: {sushiprice}</div> <div>Curve Price: {curveprice}</div> <div>Quickswap Price: {quickprice}</div> </> ); } export default App;
额外说明
- 开发环境下的双调用
useEffect是React Strict Mode的特性,用于检测潜在的副作用问题,生产环境编译后会自动移除该行为。 - 若仍存在生产环境重复请求,检查App组件是否被嵌套在频繁重渲染的父组件中,或路由配置是否导致组件重复挂载。
内容的提问来源于stack exchange,提问作者Usual Token
相关产品推荐
相关产品推荐

