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

React中useEffect循环执行致API请求过多,如何使其仅执行一次?

React中useEffect重复执行导致API请求过多的解决方案

我的React应用里,useEffect出现持续循环执行的情况,导致向API发送了大量重复请求。需要修改代码让useEffect在获取数据后仅执行一次。

我的代码

import React from 'react';
import { useState, useEffect } from "react";

function App() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null)
useEffect(() => {
if (!data) (
fetch("http://localhost:4500/coingecko")
.then(response => {
  if (response.ok) {
    return response.json()
  }
  throw response;
})
.then(data => {
  setData(data)
})
  .catch(error => {
  console.error("Error fetching data: ", error)
  setError(error)
})
.finally(() => {
  setLoading(false)
}))
}, [])

//console.log(data)

const uniswap = data&&data[0].tickers?.find(donne => donne.trade_url === 
'https://app.uniswap.org/#/swap?inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c599&outputCurrency=ETH')
const uniprice = uniswap?.converted_last?.usd
const sushiswap = data&&data[2].tickers?.find(donne => donne.trade_url === 
'https://app.sushi.com/swap?inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c599&outputCurrency=ETH')
const sushiprice = sushiswap?.converted_last?.usd
const curvefinance = data&&data[3].tickers?.find(donne => donne.base === 'DAI')
const curveprice = curvefinance?.converted_last?.usd
const quickswap = data&&data[4].tickers?.find(donne => donne.trade_url === 
'https://quickswap.exchange/#/swapinputCurrency=0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270&outputCurrency=0xbbba073c31bf03b8acf7c28ef0738decf3695683')
const quickprice = quickswap?.converted_last?.usd
console.log(uniprice)
console.log(sushiprice)
console.log(curveprice)
console.log(quickprice)

return (
<> {uniprice} </>
)
}

export default App

控制台情况

控制台多次打印价格数值,说明组件重复渲染,且API请求被多次触发。


问题分析

你当前的useEffect已经设置了空依赖数组[],理论上应该只在组件挂载时执行一次,但出现重复请求的原因主要有两点:

  1. 多余的if (!data)判断:空依赖数组已经保证useEffect仅执行一次,初始状态下data就是null,这个判断完全多余,反而容易引发逻辑误解。
  2. 语法不规范:if (!data)后使用圆括号()而非花括号{},虽然语法上可行,但不符合常规代码规范,后续维护容易出错。

解决方案

方案1:简化useEffect逻辑(最直接)

直接移除if (!data)判断,同时把圆括号改为标准花括号,空依赖数组会保证useEffect仅在组件挂载时执行一次:

useEffect(() => {
  fetch("http://localhost:4500/coingecko")
    .then(response => {
      if (response.ok) {
        return response.json()
      }
      throw response;
    })
    .then(data => {
      setData(data)
    })
    .catch(error => {
      console.error("Error fetching data: ", error)
      setError(error)
    })
    .finally(() => {
      setLoading(false)
    })
}, [])

方案2:添加请求锁(应对组件重复挂载场景)

如果App组件存在重复挂载的情况(比如被路由或父组件频繁渲染),可以添加一个状态变量标记请求是否已发起,彻底避免重复请求:

const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [requestSent, setRequestSent] = useState(false); // 请求状态锁

useEffect(() => {
  if (!requestSent) {
    setRequestSent(true); // 标记已发起请求
    fetch("http://localhost:4500/coingecko")
      .then(response => {
        if (response.ok) {
          return response.json()
        }
        throw response;
      })
      .then(data => {
        setData(data)
      })
      .catch(error => {
        console.error("Error fetching data: ", error)
        setError(error)
      })
      .finally(() => {
        setLoading(false)
      })
  }
}, [requestSent])

方案3:添加请求清理(提升代码健壮性)

虽然不会直接解决循环问题,但可以避免组件卸载时的请求泄漏,让代码更可靠:

useEffect(() => {
  const controller = new AbortController();
  const signal = controller.signal;

  fetch("http://localhost:4500/coingecko", { signal })
    .then(response => {
      if (response.ok) {
        return response.json()
      }
      throw response;
    })
    .then(data => {
      setData(data)
    })
    .catch(error => {
      if (error.name !== 'AbortError') {
        console.error("Error fetching data: ", error)
        setError(error)
      }
    })
    .finally(() => {
      setLoading(false)
    })

  // 组件卸载时取消未完成的请求
  return () => controller.abort();
}, [])

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 08:27:12