React中API返回对象数组元素点击获取唯一ID的问题
问题
我给API返回的对象数组添加了Id属性,但添加onClick方法后,点击元素打印单个元素ID时,数组内所有元素的ID都相同。请问如何实现点击元素时获取对应对象的唯一ID?
代码示例
app.js
import React from "react"; import Question from "./components/Question"; import { useState, useEffect } from "react"; import { nanoid } from "nanoid"; export default function App() { const [data, setData] = useState([]); const fetchData = () => { fetch("https://opentdb.com/api.php?amount=1&type=multiple") .then((response) => response.json()) .then((json) => { let allTasks = json.results; allTasks = allTasks.map((currentTask) => { const id = nanoid(); return { ...currentTask, isHeld: false, id: id }; }); setData(allTasks); }); }; function hold(id) { console.log(id); } useEffect(() => { fetchData(); }, []); useEffect(() => { console.log(data); }, [data]); const Elements = data.map((quiz, index) => { return ( <Question key={quiz.id} question={quiz.question} correct_answer={quiz.correct_answer} incorrect_answers={quiz.incorrect_answers} hold={() => hold(quiz.id)} isHeld={quiz.isHeld} /> ); }); return ( <div className="app"> <div className="allnow">{Elements}</div> </div> ); }
Question.jsx
import React from "react"; export default function Question(props) { return ( <div className="question"> <h2 className="question-title"> {props.question} </h2> <div className="wrong-answers"> <button className="correct-answer" onClick={props.hold}> {props.correct_answer} </button> <button className="incorrect-answer" onClick={props.hold}> {props.incorrect_answers} </button> <button className="incorrect-answer" onClick={props.hold}> {props.incorrect_answers} </button> </div> </div> ); }
控制台截图

解决方案
问题核心是闭包导致的变量绑定陷阱:在map循环中创建匿名函数时,所有函数共享同一个quiz变量的引用,最终打印的是循环结束时最后一个quiz的ID。以下是两种可行的解决方式:
方法1:优化父组件的事件绑定
在父组件的map循环中,通过箭头函数的参数绑定确保每个子组件拿到独立的ID引用,或者使用bind直接绑定参数:
const Elements = data.map((quiz) => { return ( <Question key={quiz.id} question={quiz.question} correct_answer={quiz.correct_answer} incorrect_answers={quiz.incorrect_answers} // 箭头函数包裹确保绑定当前循环的quiz.id hold={() => hold(quiz.id)} // 或者用bind绑定参数,效果一致 // hold={hold.bind(null, quiz.id)} isHeld={quiz.isHeld} /> ); });
方法2:子组件直接传递ID(更清晰)
把题目ID传递给子组件,在子组件的按钮点击事件中直接调用父方法并传入ID,同时修复错误选项的渲染问题(原代码直接渲染数组会显示字符串):
修改Question.jsx
import React from "react"; export default function Question(props) { return ( <div className="question"> <h2 className="question-title"> {props.question} </h2> <div className="wrong-answers"> <button className="correct-answer" onClick={() => props.hold(props.id)} > {props.correct_answer} </button> {/* 遍历错误选项数组,渲染单个选项 */} {props.incorrect_answers.map(answer => ( <button key={answer} className="incorrect-answer" onClick={() => props.hold(props.id)} > {answer} </button> ))} </div> </div> ); }
修改App.js的子组件传参
const Elements = data.map((quiz) => { return ( <Question key={quiz.id} id={quiz.id} // 新增传递id属性 question={quiz.question} correct_answer={quiz.correct_answer} incorrect_answers={quiz.incorrect_answers} hold={hold} // 直接传递父方法,无需提前绑定 isHeld={quiz.isHeld} /> ); });
两种方法都能确保点击按钮时,控制台打印对应题目的唯一ID,同时方法2还修复了错误选项的渲染问题,让界面显示更合理。
内容的提问来源于stack exchange,提问作者khalid dahir
相关产品推荐
相关产品推荐

