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

array.map生成组件中onClick获取正确行ID的问题排查

问题:删除按钮始终获取第一行集合ID的解决方案

问题原因

你的CollectionRow组件中,所有行的对话框(dialog)都使用了相同的id="delete"。在DOM中,id必须是唯一的,当调用document.getElementById("delete")时,只会返回页面中第一个匹配该id的元素——也就是第一行的对话框。因此无论点击哪一行的删除按钮,打开的都是第一行的对话框,对应的handleDeleteCollection函数自然只能获取到第一行的row.id。

解决方案

给每个对话框生成唯一的id,绑定到对应行的数据上,确保点击某行按钮时,打开的是该行专属的对话框。

修改后的collectionRow.tsx代码:

"use client";

import React from "react";
import { useSession } from "next-auth/react";

type TableRow = {
  id: string;
  name: string;
};

type Props = {
  row: TableRow;
  className?: string;
};

const DEFAULT_ROW: TableRow = {
  id: "0",
  name: "Collection",
};

const CollectionRow = ({ row = DEFAULT_ROW, className }: Props) => {
  // 生成唯一的对话框ID
  const dialogId = `delete-collection-${row.id}`;

  const handleDeleteCollection = async () => {
    console.log(row.id);
    // 这里可以添加实际的删除逻辑
  };

  return (
    <tr key={row.id}>
      <td className={className}>
        <div className="flex flex-col">
          <p className="text-sm">{row.name}</p>
        </div>
      </td>
      <td className={className}>
        <button
          onClick={() => {
            const dialog = document.getElementById(dialogId) as HTMLDialogElement;
            if (dialog) dialog.showModal();
          }}
          className="btn btn-primary btn-sm"
        >
          Delete
        </button>
        {/* 使用动态生成的唯一ID */}
        <dialog id={dialogId} className="modal">
          <div className="modal-box">
            <h3 className="font-bold text-lg">Delete Collection?</h3>
            <div className="modal-action">
              <form method="dialog">
                <button className="btn btn-primary">Close</button>
              </form>
              <button onClick={handleDeleteCollection} className="btn btn-error">
                Delete
              </button>
            </div>
          </div>
        </dialog>
      </td>
    </tr>
  );
};

export default CollectionRow;

额外优化建议

  1. 在page.tsx中,遍历tableRows时,组件的key建议使用row.id而非index:
{tableRows.map((row: TableRow) => {
  const isLast = row.id === tableRows[tableRows.length - 1].id;
  const classes = isLast ? "p-4" : "p-4 border-b border-primary ";

  return (
    <CollectionRow key={row.id} row={row} className={classes} />
  );
})}

使用数据唯一标识作为key,能避免React列表渲染时的潜在问题。

  1. 可以考虑用React状态来控制对话框的显示,而非直接操作DOM,更符合React的编程范式:
const CollectionRow = ({ row = DEFAULT_ROW, className }: Props) => {
  const [isDialogOpen, setIsDialogOpen] = React.useState(false);

  const handleDeleteCollection = async () => {
    console.log(row.id);
    setIsDialogOpen(false);
    // 删除逻辑
  };

  return (
    <tr key={row.id}>
      {/* ... 其他代码 ... */}
      <td className={className}>
        <button
          onClick={() => setIsDialogOpen(true)}
          className="btn btn-primary btn-sm"
        >
          Delete
        </button>
        {isDialogOpen && (
          <dialog open className="modal">
            <div className="modal-box">
              <h3 className="font-bold text-lg">Delete Collection?</h3>
              <div className="modal-action">
                <button onClick={() => setIsDialogOpen(false)} className="btn btn-primary">
                  Close
                </button>
                <button onClick={handleDeleteCollection} className="btn btn-error">
                  Delete
                </button>
              </div>
            </div>
          </dialog>
        )}
      </td>
    </tr>
  );
};

内容的提问来源于stack exchange,提问作者MrMeender

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:25:36