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

React Table map渲染子Modal仅显示最后一条数据问题

问题根因

这个问题和key属性无关,核心是实现逻辑存在4个明显错误:

  • 你遍历整个wallets列表给每一条数据都渲染了一个ModalWallets组件,所有Modal共用同一个布尔类型的modalValue开关。点击按钮将modalValue设为true时,所有Modal会同时被唤起,最后渲染的最后一条数据对应的Modal叠在最上层,视觉上就永远显示最后一条数据。你可以打开浏览器开发者工具查看DOM结构,点击按钮时会同时存在多个弹窗节点。
  • 点击行内按钮时没有记录当前操作行的唯一标识,程序根本无法区分你要打开哪条数据的弹窗。
  • 子组件中初始化余额的useEffect依赖为空数组,仅在组件首次挂载时执行一次,哪怕后续传入的余额值变化,输入框也不会同步更新。
  • 表格行渲染时用数组下标index作为key,列表数据变动时容易出现渲染错位。
修复方案
  • 不要为每一条数据单独渲染弹窗,整个页面只需要保留1个ModalWallets组件即可。
  • 新增状态存储当前要编辑的钱包数据,点击行内操作按钮时,先把当前行的数据存入该状态,再唤起弹窗。
  • 修正子组件useEffect的依赖项,保证传入的余额变化时本地状态能同步更新。
  • 表格行的key替换为每条数据唯一的uid,不要用数组下标。
修正后代码

父组件 Wallets.js 调整部分

function Wallets() {
  const [wallets, setWallets] = useState([])
  const [currentUser, setCurrentUser] = useState(null);
  // 替换原来的单一modalValue状态,拆分为弹窗开关、当前编辑数据两个状态
  const [modalOpen, setModalOpen] = useState(false);
  const [currentEditWallet, setCurrentEditWallet] = useState(null);

  // 点击编辑按钮时传入当前行的钱包数据
  const handleAddRemove = (walletItem) => {
      setCurrentEditWallet(walletItem);
      setModalOpen(true)
  }

  const handleClickEditClose = (value) => {
      setModalOpen(value)
      // 关闭弹窗时清空当前编辑数据,避免下次打开残留旧数据
      if (!value) setCurrentEditWallet(null)
  }

  // ... 其余Firestore监听逻辑保持不变

  return (
    <div className='Wallets'>
        <div className='wallets__main'>
            <div className='wallets__table__admin'>
                <CTable striped hover>
                    {/* 表头部分保持不变 */}
                    <CTableHead>
                        <CTableRow>
                            <CTableHeaderCell scope="col">No.</CTableHeaderCell>
                            <CTableHeaderCell scope="col">Name</CTableHeaderCell>
                            <CTableHeaderCell scope="col">Email</CTableHeaderCell>
                            <CTableHeaderCell scope="col">Role</CTableHeaderCell>
                            <CTableHeaderCell scope="col">Balance</CTableHeaderCell>
                            <CTableHeaderCell scope="col">Action</CTableHeaderCell>
                        </CTableRow>
                    </CTableHead>
                    <CTableBody>
                        {wallets && wallets.map((item, index) => {
                            item.serial = index + 1;
                            {/* key替换为唯一uid,不要用index */}
                            return <CTableRow key={item.uid}>
                                <CTableHeaderCell scope="row">{item.serial}</CTableHeaderCell>
                                <CTableDataCell>{item.data.name}</CTableDataCell>
                                <CTableDataCell>{item.data.email}</CTableDataCell>
                                <CTableDataCell>{item.data.role}</CTableDataCell>
                                <CTableDataCell>${" "}{item.data.balance}</CTableDataCell>
                                <CTableDataCell>
                                    <CButton
                                        {/* 点击时传入当前行数据 */}
                                        onClick={() => handleAddRemove(item)}
                                    >
                                        Add Amount
                                    </CButton>
                                </CTableDataCell>
                            </CTableRow>
                        })}
                    </CTableBody>
                </CTable>
                {/* 删除原来遍历wallets渲染Modal的代码,仅在有选中编辑数据时渲染单个弹窗 */}
                {currentEditWallet && (
                    <ModalWallets
                        modalValue={modalOpen}
                        handleClickEditClose={handleClickEditClose}
                        Email={currentEditWallet.data.email}
                        Role={currentEditWallet.data.role}
                        Balance={currentEditWallet.data.balance}
                        Name={currentEditWallet.data.name}
                        id={currentEditWallet.uid}
                    />
                )}
            </div>
        </div>
    </div>
  )
}

子组件 ModalWallets.js 调整部分

function ModalWallets({ modalValue, handleClickEditClose, Email, Role, Balance, Name, id }) {
  const [balanceState, setBalanceState] = useState(0);

  // ... 其余更新逻辑保持不变

  // 给useEffect加上Balance依赖,保证传入余额变化时同步更新本地状态
  useEffect(() => {
      setBalanceState(Balance)
  }, [Balance])

  // ... 其余弹窗渲染逻辑保持不变
}
相关截图
  • 父组件(承载数据表格、触发子Modal弹窗的操作按钮)
    父组件效果截图
  • 问题现象:点击表格第一行(对应邮箱为walletUser@gmail.com),弹窗却展示第三行数据
    问题现象截图

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 04:27:14