React中useEffect传参及模态框数据加载报错问题排查
问题
我是React新手,对useEffect概念理解有困惑。在Portfolio组件中,通过cardData数组自动生成卡片,每张卡片映射生成带对应数据id的按钮。需求是鼠标悬停时获取按钮id,匹配cardData中的对应对象,点击按钮时打开模态框展示该对象内容。但将mouseId传入handleData时返回undefined,出现Cannot read properties of undefined (reading 'title')报错,硬编码数值则能正常运行。怀疑是useEffect无法通过props传递数据,或是数据在点击后才设置导致模态框无法获取内容。
相关核心代码:
function Portfolio(){ const [modalOpen, setModalOpen] = useState(false); const close = () => setModalOpen(false); const open = () => setModalOpen(true) ; const [letterClass, setLetterClass] = useState("text-animate"); const [ mouseId, setMouseId ] = useState(1); const [modalData, setModalData] = useState([]); useEffect(() => { setTimeout(() => { return setLetterClass('text-animate-hover') }, 3000) }, []) function handleMouseOver(event) { setMouseId(event.target.id) } function handleData(data){ setModalData(cardData.find(obj => obj.id === data)) } // 调用handleData的useEffect useEffect(() => { handleData(mouseId) }, [mouseId]) // 点击事件 function handleClick() { if (!modalOpen) { open(); } else if (modalOpen) { close(); } } return (<> <div className="port-content"> <div className="container portfolio-page"> <div className="port-text-zone"> <h1> <AnimatedLetters idx={15} letterClass={letterClass} strArray={["M","y"," ","p","o","r","t","f","o","l","i","o","."]}/> </h1> <p>Since I'm such a versatile junior, I've worked on many different types of projects. My projects include design, front-end development and back-end development.</p> </div> </div> <GeneratedCards id={handleClick} mouse={handleMouseOver}/> </div> {modalOpen && <> <Modal modalOpen={modalOpen} handleClose={close} /> <ModalContent title={modalData.title} content={modalData.description} desc1={modalData.modalDescription1} desc2={modalData.modalDescription2} desc3={modalData.modalDescription3} projectLink={modalData.title} /> </>} <Loader type="ball-grid-beat" /> </>) } export default Portfolio;
解决方案
1. 核心问题:类型不匹配
event.target.id返回的是字符串类型,而cardData中的id是数值类型,使用全等===匹配时找不到对应对象,返回undefined,导致modalData为undefined,访问modalData.title时触发报错。
2. 优化修改步骤
步骤1:修复类型匹配问题
在handleMouseOver中将字符串id转为数值:
function handleMouseOver(event) { // 将字符串id转为数值类型 setMouseId(Number(event.target.id)) }
或者在handleData中转换匹配的类型:
function handleData(data){ setModalData(cardData.find(obj => obj.id === Number(data))) }
步骤2:移除冗余的useEffect监听
没必要通过useEffect监听mouseId来更新modalData——悬停时提前加载数据是无意义的,应该在点击按钮时直接获取对应数据,减少不必要的状态更新:
- 修改
handleClick,让它接收卡片id参数,直接获取数据并打开模态框:
function handleClick(cardId) { // 转换类型并匹配数据 const selectedData = cardData.find(obj => obj.id === Number(cardId)); setModalData(selectedData); setModalOpen(true); }
- 在
GeneratedCards组件中,给按钮的点击事件传递对应卡片的id(假设卡片数据是card):
// GeneratedCards内部的按钮元素 <button id={card.id} onClick={() => props.id(card.id)} onMouseOver={() => props.mouse(card.id)} > {/* 按钮内容 */} </button>
同时修改handleMouseOver直接接收id:
function handleMouseOver(cardId) { setMouseId(Number(cardId)) }
步骤3:处理初始状态避免渲染报错
将modalData的初始状态设为null,并在渲染ModalContent时添加判断,避免初始或数据未加载时访问属性报错:
// 初始化状态 const [modalData, setModalData] = useState(null); // 渲染部分 {modalOpen && modalData && <> <Modal modalOpen={modalOpen} handleClose={close} /> <ModalContent title={modalData.title} content={modalData.description} desc1={modalData.modalDescription1} desc2={modalData.modalDescription2} desc3={modalData.modalDescription3} projectLink={modalData.title} /> </>}
或者使用可选链操作符简化:
<ModalContent title={modalData?.title} content={modalData?.description} desc1={modalData?.modalDescription1} desc2={modalData?.modalDescription2} desc3={modalData?.modalDescription3} projectLink={modalData?.title} />
内容的提问来源于stack exchange,提问作者Henry Ford
相关产品推荐
相关产品推荐

