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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:12:29