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

React读取localStorage报insertRow空错误 二次点击返回首值undefined

问题根因

  • 触发insertRow报错是因为React状态更新为异步执行:调用setTable_show_Deposit、setHistory等修改状态的方法后,DOM不会立刻渲染,此时直接用document.getElementById获取表格DOM会返回null,调用方法自然报错。第二次点击时对应状态已经为true,DOM已经渲染完成,所以可以正常获取元素执行后续逻辑。
  • 返回第一个值为undefined有两个原因:
    1. 初始化collections_transaction_deposite、collections_transaction_withdraw两个状态时,初始值设置为[{}],数组默认携带了一个空对象,后续存入localStorage、读取渲染时这个空对象对应的属性自然都是undefined。
    2. 调用setState更新交易数组后,立刻将当前数组存入localStorage,而setState是异步的,此时拿到的还是更新前的旧数组,导致存储的内容永远比实际操作少一条,也会出现取值异常。

修复方案

1. 修复异步渲染导致DOM获取失败问题

把操作DOM的逻辑放到setTimeout里,等状态更新、DOM渲染完成后再执行,也可以用useEffect监听对应状态的变化,状态变更后再执行DOM操作。以下为修改成本最低的setTimeout方案,以Deposite_show_table方法为例:

const Deposite_show_table = () => {
    setTable_show_Deposit(true);
    setTable_show_WithDraw(false);
    // 加setTimeout等DOM渲染完成
    setTimeout(() => {
        if (table !== "") {
            const table = document.getElementById('deposite_table');
            // 加DOM存在判断,避免极端情况报错
            if (!table) return
            myArr = JSON.parse(localStorage.getItem('transaction_Deposite')) || [];
            console.log(myArr);
            for (let i = 0; i < myArr.length; i++) {
                const row = table.insertRow(i);
                row.innerHTML = "<td>" + myArr[i].transaction_type + "</td>" + "<td>" + myArr[i].Amount + "</td>" + "<td>" + myArr[i].time + "</td>" + "<td>" + myArr[i].Balance + "</td>" + "<td>" + myArr[i].interest + "</td>"
            }
        }
        else {
            console.log("Empty");
        }
    }, 0)
}

WithDraw_show_table、RecentTrans方法都按同样的逻辑修改,把操作DOM的代码包裹在setTimeout里即可。

2. 修复第一个值为undefined问题

  • 把两个交易数组的初始值改成空数组:
// 原错误写法
// const [collections_transaction_deposite, setCollections_transaction_deposite] = useState([obj]);
// const [collections_transaction_withdraw, setCollections_transaction_withdraw] = useState([object]);
// 修改后
const [collections_transaction_deposite, setCollections_transaction_deposite] = useState([]);
const [collections_transaction_withdraw, setCollections_transaction_withdraw] = useState([]);
  • 把localStorage存储逻辑放到setState的回调里,确保存的是更新后的数组,以Deposite方法为例:
const Deposite = () => {
    const event = new Date().toLocaleString();
    const setter = localStorage.getItem(getter)
    const store = parseInt(setter) + parseInt(init);
    localStorage.setItem(getter, store);
    let interset_Amount = '';
    if (store < 0) {
        interset_Amount = store;
    }
    else {
        interset_Amount = 0;
    }
    const newObj = {
        "transaction_type": 'Deposite',
        "Amount": document.getElementById('depinput').value,
        "time": event,
        "Balance": store,
        "interest": interset_Amount
    }
    // setState回调里存localStorage,确保取到最新数组
    setCollections_transaction_deposite(pre => {
        const newArr = [newObj, ...pre]
        localStorage.setItem("transaction_Deposite", JSON.stringify(newArr))
        return newArr
    })
}

Withdraw方法按同样逻辑修改即可。

补充优化建议

不建议直接操作DOM插入表格行,符合React开发规范的写法是直接把交易数组的渲染逻辑写到JSX里,不需要手动操作DOM,能从根本上避免这类异步渲染导致的DOM操作问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 20:15:03