React中useRef绑定列表元素时正确获取对应元素文本方法
问题原因
你在循环渲染的列表项里给所有p标签绑定了同一个useRef实例,React的ref绑定循环生成的多个DOM元素时,最终只会保留最后一个渲染完成的DOM元素的引用,所以不管点击哪个条目的按钮,打印的永远是最后一条电子书的书名段落,无法匹配当前点击的条目。
修复方案
两种实现方式都可以准确拿到当前点击条目的对应内容,优先选第一种:
方案1:点击事件直接传入当前条目数据(最推荐,无需操作DOM)
完全不需要给p标签绑定ref,点击按钮时直接把当前循环项的书名数据传给处理函数即可,符合React数据驱动的开发逻辑,性能更好也不会出现引用错位问题:
import React from 'react' import "./Styles/Ebook.css" function Ebook() { let ebookData = JSON.parse(sessionStorage.getItem("ebook")); // 存储收藏内容的数组 const favouritesList = [] // 收藏按钮点击逻辑 const handleAddFavourite = (bookName) =>{ console.log("当前选中书名:", bookName) // 逻辑验证通过后直接存入数组即可 favouritesList.push(bookName) console.log("当前收藏列表:", favouritesList) } return ( <section id="musicRender"> {ebookData.results.map((ebook, i)=>{ return ( <div key={i} className='ebookContentContainer'> <div className="ebookPicture"> <img src={ebook.artworkUrl100} alt={ebook.trackName} /> </div> <div className="ebook-description"> <p className="ebookAuthor">Author: {ebook.artistName}</p> <p className='ebookAName'>Book Name: {ebook.trackName}</p> <p className="price">Price: R{(ebook.price * 15.36).toFixed(0)}</p> {/* 点击时直接传入当前条目的书名 */} <button onClick={() => handleAddFavourite(ebook.trackName)} className="favourites-btn">Add To Favourites</button> </div> </div>) })} </section> ) } export default Ebook
方案2:必须取DOM文本时,用ref回调存储对应项的DOM
如果后续有操作DOM样式等必须拿DOM节点的需求,不要用单个ref实例,改用ref回调把每个列表项的DOM存在对象中,点击时按索引取对应DOM即可:
import React from 'react' import "./Styles/Ebook.css" import { useRef } from 'react'; function Ebook() { // 用ref存储对象,key为列表索引,value为对应p标签DOM const bookNameRefs = useRef({}); let ebookData = JSON.parse(sessionStorage.getItem("ebook")); const elementLogFunction = (index) =>{ // 按索引取对应DOM,读取文本内容 const currentBookP = bookNameRefs.current[index] console.log(currentBookP.textContent) } return ( <section id="musicRender"> {ebookData.results.map((ebook, i)=>{ return ( <div key={i} className='ebookContentContainer'> <div className="ebookPicture"> <img src={ebook.artworkUrl100} alt={ebook.trackName} /> </div> <div className="ebook-description"> <p className="ebookAuthor">Author: {ebook.artistName}</p> {/* 用ref回调将当前DOM存入refs对象的对应索引位 */} <p ref={el => bookNameRefs.current[i] = el} className='ebookAName'>Book Name: {ebook.trackName}</p> <p className="price">Price: R{(ebook.price * 15.36).toFixed(0)}</p> <button onClick={() => elementLogFunction(i)} className="favourites-btn">Add To Favourites</button> </div> </div>) })} </section> ) } export default Ebook
注意事项
- 日常React开发优先用方案1,尽量避免直接操作DOM,直接读取渲染用的源数据是最稳妥的实现方式
- 单个
useRef实例只能存储一个值,不能直接绑定到循环渲染的多个元素上,否则永远只能拿到最后一个渲染的元素引用
内容的提问来源于stack exchange,提问作者George Marwanqana
相关产品推荐
相关产品推荐

