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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 03:12:33