React报错:'children'未定义,按钮批量显示文本功能开发遇阻
问题:React循环按钮的状态初始化错误与功能实现
我想实现点击按钮时,循环中的每个按钮切换显示对应文本的功能。一开始用useState创建状态:
const [CouponCode, setCouponCode] = useState(Array.from({length:children.length}).fill(false))
但出现了children未定义的错误;尝试换成this.props.children.length后,又出现了props相关的错误。
附上相关代码:
import React,{useState,useEffect} from 'react'; import axios from"axios"; import Card from '@mui/material/Card'; import { Box, Grid, ListItemText } from '@mui/material'; function FetchData(props) { const [records, setRecords] = useState([]); const [CouponCode, setCouponCode] = useState(Array.from({length:children.length}).fill(false)) useEffect(() => { axios({ method: "GET", url: "http://127.0.0.1:5000/coupons", headers: {}, params: {}, }) .then((response) => { console.log("response :", response.data); setRecords(response.data); }) .catch((error) => { console.log(error); }); }, []); return ( <div styles={{padding:30}}> <Grid container spacing={8} justifyContent="center"> {records?.map((list,index)=>( <Grid item xs={10} key={index}> <Card variant='outlined'sx={{display:"block",width:"70vw"}}> <Box sx={{ width: '95px', height: '100px', boxShadow: 0, margin: '10px',top:"0" }}> <img width="95px" height="100px" alt='Logo' srcSet={list.title_logo}/> <ListItemText sx={{display:"inline",position:"absolute"}} primaryTypographyProps={{fontSize:"2rem"}} secondaryTypographyProps={{fontSize:"1.1rem",style: { whiteSpace: 'wrap', overflow: 'hidden', textOverflow: 'ellipsis'}}} primary={<div><span>{list.offer_title}</span></div>} secondary={list.description}/> {list.type_of_voucher==="Coupons"? <button onClick={()=> setCouponCode(prevState => { const tutorsArr = [...prevState]; tutorsArr[index] = !tutorsArr[index] return tutorsArr;})}>{CouponCode[index] ? "Get Coupon Code":""}</button> :<button style={{display:'inline-flex',float:'right'}} onClick={()=> setCouponCode(prevState => { const tutorsArr = [...prevState]; tutorsArr[index] = !tutorsArr[index] return tutorsArr;})}>{CouponCode[index] ?"Get Deals":""} </button>} </Box> </Card> </Grid> ))}; </Grid> </div> ); }; export default FetchData;
解决方案
1. 错误原因
- 组件内未定义
children变量,你实际需要的是接口返回的records数组长度,而非组件子元素。 - 函数组件不能使用
this.props,需直接用参数props,但这里props.children并非你需要的内容。 - 组件初始化时
records是空数组,直接用长度初始化状态会导致逻辑异常。
2. 修复步骤
(1)初始化状态为空数组
将CouponCode的初始化改为空数组,避免依赖未定义的变量:
const [CouponCode, setCouponCode] = useState([]);
(2)监听records变化,动态同步状态长度
添加useEffect监听records的更新,当接口返回数据后,同步调整CouponCode数组的长度,确保和records条目数一致:
useEffect(() => { // 当records获取到数据后,初始化状态数组,每个元素默认false setCouponCode(Array.from({ length: records.length }).fill(false)); }, [records]);
(3)调整按钮文本逻辑(可选)
你当前的按钮文本逻辑是状态为true时显示文本,false时为空,如果想实现「默认显示按钮文案,点击后切换为对应内容」的效果,可以修改为:
// 优惠券按钮 <button onClick={()=> setCouponCode(prevState => { const tutorsArr = [...prevState]; tutorsArr[index] = !tutorsArr[index]; return tutorsArr; })}> {CouponCode[index] ? list.coupon_code : "Get Coupon Code"} </button> // 优惠活动按钮 <button style={{display:'inline-flex',float:'right'}} onClick={()=> setCouponCode(prevState => { const tutorsArr = [...prevState]; tutorsArr[index] = !tutorsArr[index]; return tutorsArr; })}> {CouponCode[index] ? "查看活动详情" : "Get Deals"} </button>
3. 完整修复后的代码
import React,{useState,useEffect} from 'react'; import axios from"axios"; import Card from '@mui/material/Card'; import { Box, Grid, ListItemText } from '@mui/material'; function FetchData(props) { const [records, setRecords] = useState([]); const [CouponCode, setCouponCode] = useState([]); useEffect(() => { axios({ method: "GET", url: "http://127.0.0.1:5000/coupons", headers: {}, params: {}, }) .then((response) => { console.log("response :", response.data); setRecords(response.data); }) .catch((error) => { console.log(error); }); }, []); // 监听records变化,同步更新CouponCode数组长度 useEffect(() => { setCouponCode(Array.from({ length: records.length }).fill(false)); }, [records]); return ( <div style={{padding:30}}> <Grid container spacing={8} justifyContent="center"> {records?.map((list,index)=>( <Grid item xs={10} key={index}> <Card variant='outlined'sx={{display:"block",width:"70vw"}}> <Box sx={{ width: '95px', height: '100px', boxShadow: 0, margin: '10px',top:"0" }}> <img width="95px" height="100px" alt='Logo' srcSet={list.title_logo}/> <ListItemText sx={{display:"inline",position:"absolute", marginLeft: 10}} primaryTypographyProps={{fontSize:"2rem"}} secondaryTypographyProps={{fontSize:"1.1rem",style: { whiteSpace: 'wrap', overflow: 'hidden', textOverflow: 'ellipsis', width: '60vw' }}} primary={<div><span>{list.offer_title}</span></div>} secondary={list.description}/> {list.type_of_voucher==="Coupons"? <button onClick={()=> setCouponCode(prevState => { const tutorsArr = [...prevState]; tutorsArr[index] = !tutorsArr[index]; return tutorsArr; })}> {CouponCode[index] ? list.coupon_code : "Get Coupon Code"} </button> :<button style={{display:'inline-flex',float:'right'}} onClick={()=> setCouponCode(prevState => { const tutorsArr = [...prevState]; tutorsArr[index] = !tutorsArr[index]; return tutorsArr; })}> {CouponCode[index] ? "查看活动详情" : "Get Deals"} </button>} </Box> </Card> </Grid> ))}; </Grid> </div> ); }; export default FetchData;
内容的提问来源于stack exchange,提问作者Shivam Misra
相关产品推荐
相关产品推荐

