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
相关产品推荐
相关产品推荐

