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;
额外优化建议
- 在
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列表渲染时的潜在问题。
- 可以考虑用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
相关产品推荐
相关产品推荐

