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

React点击按钮调用货币API:useEffect报错,求正确代码位置

问题解答

是否需要去掉useEffect?

是的,完全可以去掉这个useEffect。当前的useEffect会在组件挂载时自动发起一次请求,但你的需求是点击按钮时触发API调用,这个自动执行的逻辑不符合需求,留着反而会在不必要的时机发起请求。

API调用应该放在哪里?

你需要把API请求代码直接放到handleClickOpen函数里,或者封装成独立函数后在handleClickOpen中调用。注意:React的Hook只能在组件顶层或自定义Hook里调用,不能直接在事件处理函数中使用useEffect——这就是你之前尝试把useEffect放进handleClickOpen时报错的原因。

修改后的代码示例

import * as React from 'react';
import axios from "axios"
import PropTypes from 'prop-types';
import Button from '@mui/material/Button';
import Avatar from '@mui/material/Avatar';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemAvatar from '@mui/material/ListItemAvatar';
import ListItemText from '@mui/material/ListItemText';
import DialogTitle from '@mui/material/DialogTitle';
import Dialog from '@mui/material/Dialog';
import { blue } from '@mui/material/colors';


const emails = [
  {title: "Pound sterling", symbol: "£", id: 1, acronym: "GBP"},
  {title: "Euro", symbol: "€", id: 2, acronym: "EUR"},
  {title: "Nigerian Naira", symbol: "₦", id: 3, acronym: "NGN"},
  {title: "Saudi Arabian riyal", symbol: "SR", id: 4, acronym: "SAR"},
  {title: "Indian rupee", symbol: "₹", id: 5, acronym: "INR"},
  {title: "United States dollar", symbol: "$", id: 6, acronym: "USD"},
]

function SimpleDialog(props) {
  const { onClose, selectedValue, open } = props;

  const handleClose = () => {
    onClose(selectedValue);
  };

  const handleListItemClick = (value) => {
    onClose(value);
  };

  return (
    <Dialog onClose={handleClose} open={open}>
      <DialogTitle>Choose a currency</DialogTitle>
      <List sx={{ pt: 0 }}>
        {emails.map((email) => (
          <ListItem button onClick={() => handleListItemClick(email.symbol)} key={email.id}>
            <ListItemAvatar>
              <Avatar sx={{ bgcolor: blue[100], color: blue[600] }}>
                {email.symbol}
              </Avatar>
            </ListItemAvatar>
            <ListItemText primary={email.title} />
          </ListItem>
        ))}
      </List>
    </Dialog>
  );
}

SimpleDialog.propTypes = {
  onClose: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
  selectedValue: PropTypes.string.isRequired,
};

export default function SimpleDialogDemo({selectedValue, setSelectedValue}) {
  const [open, setOpen] = React.useState(false);

  // 封装API请求函数
  const fetchCurrencyData = async () => {
    const options = {
      method: 'GET',
      url: 'https://exchangerate-api.p.rapidapi.com/rapid/latest/USD',
      headers: {
        'X-RapidAPI-Key': 'c0d2e70417msh3bde3b7dbe9e25ap12748ejsncd1fe394742c',
        'X-RapidAPI-Host': 'exchangerate-api.p.rapidapi.com'
      }
    };
    
    try {
      const response = await axios.request(options);
      console.log(response.data);
      // 可根据需求将数据存入state,比如setCurrencyData(response.data)
    } catch (error) {
      console.error(error);
    }
  };

  const handleClickOpen = () => {
    setOpen(true);
    // 点击按钮时触发API请求
    fetchCurrencyData();
  };

  const handleClose = (value) => {
    setOpen(false);
    setSelectedValue(value);
  };
 
  return (
    <div>
      <Button  variant="text" onClick={handleClickOpen} sx={{
         ml: 30,
         mb: 0,
         p: 0,
          }}>
        {selectedValue} {emails.find(email => email.symbol===selectedValue).acronym}
      </Button>
      <SimpleDialog
        selectedValue={selectedValue}
        open={open}
        onClose={handleClose}
      />
    </div>
  );
}

关键说明

  • 移除了SimpleDialog组件中自动执行的useEffect,避免不必要的请求
  • 将API请求封装为独立的fetchCurrencyData函数,在handleClickOpen中调用,满足点击触发的需求
  • 使用async/await简化异步代码逻辑,也可以保留原有的.then/.catch写法
  • 严格遵循React Hook规则:只在组件顶层或自定义Hook中使用Hook,不在事件处理函数内调用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:40:31