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

React货币转换器开发:多axios并发请求与组件逻辑正确实现

核心问题定位

你目前的实现本质是把原生JavaScript的DOM操作逻辑硬套进React组件,完全违背React 状态驱动UI 的核心设计,具体偏差点:

  • 全程没有使用React内置的状态存储机制,临时定义的汇率数组、输入值都是局部变量,组件重渲染后会直接丢失
  • 沿用原生JS的事件绑定逻辑:在axios回调里通过addEventListener给按钮绑事件、直接操作DOM元素的value/textContent,在React中完全不需要这种手动DOM操作
  • 作用域嵌套混乱:把计算函数、接口请求、事件绑定都塞在嵌套的函数作用域里,变量根本无法在正确的执行时机被访问
  • 存在基础语法错误:比如自定义组件名和导出名不一致、React事件用了原生onclick而非onClick、class属性没改成React要求的className、直接引用未定义的input/button/endresult等DOM节点
符合React规范的axios多接口集成实现思路
  1. 状态拆分:用useState把所有动态变化的数据单独存成可响应的状态,包括:
    • 接口拉取到的币种汇率列表
    • 用户输入的兑换金额
    • 用户选择的目标币种
    • 最终计算的兑换结果
    • 接口加载、错误提示状态
  2. 请求时机:用useEffect在组件首次挂载完成后,发起axios并行请求——你之前写的axios.all并行请求的思路是正确的,只是拿到结果后要把数据存到React状态里,不要临时塞在闭包里
  3. 事件绑定:所有交互逻辑直接绑定到React的合成事件上,比如按钮的点击、输入框的内容变化、下拉框的选择。计算逻辑直接从状态里取数据运算,结果存回状态后由React自动更新UI,完全不需要手动操作DOM节点
可直接复用的正确实现代码
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './Przelicznik.css';

// 固定请求接口常量
const CURRENCY_API_ENDPOINTS = [
  "http://api.nbp.pl/api/exchangerates/rates/A/CHF/",
  "http://api.nbp.pl/api/exchangerates/rates/A/EUR/",
  "http://api.nbp.pl/api/exchangerates/rates/A/USD/"
];

const Currencies = () => {
  // 初始化响应式状态
  const [currencyRates, setCurrencyRates] = useState([]);
  const [inputAmount, setInputAmount] = useState('1');
  const [selectedCurrency, setSelectedCurrency] = useState('CHF');
  const [calcResult, setCalcResult] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [fetchError, setFetchError] = useState('');

  // 组件挂载完成后拉取汇率数据
  useEffect(() => {
    const fetchRates = async () => {
      setIsLoading(true);
      try {
        // 批量并行发起所有接口请求
        const responses = await axios.all(
          CURRENCY_API_ENDPOINTS.map(apiUrl => axios.get(apiUrl))
        );
        // 整理接口返回的结构化数据
        const formattedRates = responses.map(res => ({
          code: res.data.code,
          midRate: res.data.rates[0].mid
        }));
        setCurrencyRates(formattedRates);
      } catch (err) {
        setFetchError('汇率数据加载失败,请稍后重试');
        console.error(err);
      } finally {
        setIsLoading(false);
      }
    };
    fetchRates();
  }, []);

  // 兑换计算逻辑
  const handleCalculate = () => {
    if (!inputAmount) {
      alert("Wpisz kwotę");
      return;
    }
    // 匹配选中币种的实时汇率
    const matchedRate = currencyRates.find(item => item.code === selectedCurrency);
    if (!matchedRate) return;
    // 计算并格式化结果
    const result = (parseFloat(inputAmount) * matchedRate.midRate).toFixed(2);
    setCalcResult(`${result} zł`);
  };

  return (
    <div className="container-przel">
      {isLoading && <p>数据加载中...</p>}
      {fetchError && <p className="error">{fetchError}</p>}
      <input 
        className="input" 
        placeholder="0" 
        value={inputAmount}
        onChange={(e) => setInputAmount(e.target.value)}
      />
      <select 
        className="currencies"
        value={selectedCurrency}
        onChange={(e) => setSelectedCurrency(e.target.value)}
      >
        <option value="CHF">CHF</option>
        <option value="EUR">EUR</option>
        <option value="USD">USD</option>
      </select>
      <button 
        className="button" 
        type="button" 
        onClick={handleCalculate}
        disabled={isLoading}
      >
        Przelicz!
      </button>
      <p className="endresult">{calcResult}</p>
    </div>
  );
};

export default Currencies;
关键设计说明
  • 之前尝试用类组件搭配this.state的思路本质没有问题,类组件和函数组件的核心逻辑都是状态驱动UI:所有UI展示的内容,都是状态变化后由React自动重新渲染输出的,不需要手动修改DOM的文本、属性值
  • 并行请求不需要手动逐个定义请求实例,将接口地址存入数组后通过axios.all批量发起即可,代码更简洁易维护
  • 计算逻辑完全不依赖DOM节点的引用,所有运算需要的值都从React状态中获取,从根源上避免闭包导致的变量值不同步问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.30 12:15:03