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

React汇率转换应用API多次调用致429错误排查求助

解决React汇率转换应用中API重复调用与多次渲染问题

问题根源分析

API重复调用原因

  1. React Strict Mode 双重执行:开发环境下Strict Mode会主动双重执行副作用函数(如useEffect),导致fetchCurrency被触发两次。
  2. 无请求拦截机制:Store中的fetchCurrency函数没有判断请求状态,每次调用都会直接发起新请求,即便数据已经存在。

多次console.log原因

  1. 组件重渲染触发:组件初始渲染、Store状态更新、Strict Mode双重执行都会引发组件重渲染,每次重渲染都会执行console.log。
  2. 多余状态同步:额外使用code这个useState同步Store数据,导致每次Store更新都会触发setCode,进而引发额外重渲染。

解决方案

1. 阻止API重复调用

方法一:在Store中添加请求状态控制

通过新增isLoading和hasFetched状态,确保仅在未请求、未加载时发起API调用:

import { create } from "zustand";
import { devtools } from "zustand/middleware";
import { getCurrencyCode } from "./services/CurrencyExchangeService";
import { CurrencyCode } from "./types";

type CurrencyExchangeStore={
    currencyCode : CurrencyCode[]
    isLoading: boolean
    hasFetched: boolean
    fetchCurrency: () => Promise<void>
}
export const useCurrencyExchangeStore = create<CurrencyExchangeStore>()(devtools((set, get)=>({
    currencyCode: [] as CurrencyCode[],
    isLoading: false,
    hasFetched: false,
    fetchCurrency: async ()=>{
        const { isLoading, hasFetched } = get();
        // 已加载或正在请求时直接返回
        if (isLoading || hasFetched) return;
        
        set({ isLoading: true });
        try {
            const currencyCode = await getCurrencyCode();
            set(()=>({
                currencyCode,
                hasFetched: true
            })); 
        } catch (err) {
            console.error('获取货币代码失败:', err);
        } finally {
            set({ isLoading: false });
        }
    }
})))

方法二:给API请求添加缓存

在请求函数中加入内存/本地存储缓存,避免重复请求:

import axios from "axios";
import { CurrencyCodesSchema } from "../schema/currency-exchange-schema";
import { CurrencyCode } from "../types";

const appId= import.meta.env.VITE_API_KEY
// 内存缓存
let currencyCache: CurrencyCode[] | null = null;

export const getCurrencyCode = async()=>{
    // 优先返回缓存数据
    if (currencyCache) return currencyCache;
    
    // 尝试读取本地存储的持久化缓存
    const localCache = localStorage.getItem('currencyCodes');
    if (localCache) {
        currencyCache = JSON.parse(localCache);
        return currencyCache;
    }
    
    const url = `https://api.currencyapi.com/v3/currencies?apikey=${appId}&currencies=`
    
    const {data: {data}} = await axios(url)

    const arrayCurrency = CurrencyCodesSchema.safeParse(Object.entries(data).map(([code, currency])=>{
      return{
          id : code,
          data : currency
      }
    }))

    if(arrayCurrency.success){
        currencyCache = arrayCurrency.data;
        localStorage.setItem('currencyCodes', JSON.stringify(arrayCurrency.data));
        return arrayCurrency.data
    }
}

2. 减少不必要的重渲染与日志输出

移除多余的状态同步

直接从Store读取currencyCode,无需额外useState同步,减少重渲染触发点:

import { useEffect } from "react"
import { useCurrencyExchangeStore } from "../store"

const Form = () => {
    const { currencyCode, fetchCurrency } = useCurrencyExchangeStore()
    
    useEffect(()=>{fetchCurrency()},[])
    
    // 仅在数据更新时打印,避免无意义的空数组日志
    useEffect(() => {
        if (currencyCode.length > 0) {
            console.log(currencyCode);
        }
    }, [currencyCode])
    
    return (
        <div>Form</div>
    )
}

export default Form

关于Strict Mode双重渲染

开发环境下的双重执行是React的调试机制,生产环境会自动消失,不建议长期关闭该模式,它能帮助提前发现组件的潜在问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 18:03:10