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

如何在React Hooks中为表格添加行且避免出现重复行?

问题原因

  • 闭包旧值问题:你更新tableRows时直接使用了当前作用域捕获的tableRows,而getCurrentPrice是异步函数,接口返回时如果组件已经触发过重渲染,当前作用域里的tableRows还是旧值,拼接后就会出现旧数据重复插入的情况。
  • 全局索引异常:tableRowIndex定义在组件外部属于全局变量,组件多次挂载、卸载都会导致计数异常;同时你渲染TableRow时错误将全局tableRowIndex作为所有行的key属性值,React检测到key重复就会出现渲染异常,产生重复行。
  • 直接修改入参:你直接修改了传入的inputs对象的属性,属于引用对象修改,也可能引发意外的状态异常。

修复方案

核心改动点

  1. state更新改用函数式写法,直接拿到最新的state值,规避闭包旧值问题
  2. 行索引移入组件内部用useRef存储,避免全局污染,同时渲染时绑定每行自身的index作为key
  3. 新增行时生成新的对象,不直接修改入参inputs

修复后完整代码

import { useState, useRef } from 'react';
import axios from 'axios';

const CoinTable = () => {
    const baseURL = 'endpoint/';
    const [tableRows, setRows] = useState([] as any);
    // 行索引用useRef存储,重渲染不会重置,也不会污染全局
    const tableRowIndexRef = useRef(0);

    const getCurrentPrice = async (inputs: any) => {
        const response = await axios.get(`${baseURL}${inputs.currency}/USD`)
        const currentPrice = response.data
        // 生成新行对象,不直接修改入参
        const newRow = {
            ...inputs,
            cryptoPrice: currentPrice.rate,
            amtCrypto: (inputs.amount / currentPrice.rate).toFixed(8),
            index: ++tableRowIndexRef.current
        }
        addNewRow(newRow)
    }

    const addNewRow = (newRow: any) => {
        // 函数式更新获取最新的rows列表
        setRows(prevRows => [...prevRows, newRow])
    }

    const rows = tableRows.map((row: any) => {
        return (
            <TableRow
                key={row.index} // 绑定当前行自身的index作为key
                addNewRow={addNewRow}
                removeRow={removeRowHandler}
                getCurrentPrice={getCurrentPrice}
                row={row}
            />
        )
    })
    
    return (
        <>
            <AddItem
                getCurrentPrice={getCurrentPrice}
            />
            {tableRows.length > 0 &&
                <table>
                    <tbody>
                        <tr>
                            <th>Merchant</th>
                            <th>Item</th>
                            <th>Amount(Crypto)</th>
                            <th>Currency</th>
                            <th>Price/crypto(USD)</th>
                            <th>Amount(USD)</th>
                        </tr>
                        {rows}
                    </tbody>
                </table>
            }
        </>
    )
}

export default CoinTable;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 17:54:04