如何用Web3.js检测交易确认并在React中重渲染链上待办列表
问题解决:链上待办创建后无法检测交易确认并更新列表
问题根源
你当前代码里调用createTask时,监听的是sent事件——这个事件仅在交易被节点接收时触发,而非交易被打包确认上链的时机。此时链上数据还未完成更新,调用loadTasks自然无法获取到新创建的待办事项。
解决方案
1. 切换监听交易确认事件
把sent事件替换为receipt(交易打包进区块后返回回执)或confirmation(指定确认次数后触发)事件,确保交易上链后再刷新列表。
2. 优化任务加载逻辑
原loadTasks中循环调用setTask会导致多次不必要的组件重渲染,改用Promise.all批量获取任务后一次性更新状态,提升性能同时避免状态不一致。
修改后的核心代码
// 优化loadTasks函数 const loadTasks = async () => { if (!contract) return; // 避免contract未初始化时调用 const taskCount = await contract.methods.taskCount().call(); setTaskCount(taskCount); // 批量获取所有任务,减少状态更新次数 const tasks = await Promise.all( Array.from({ length: taskCount }, (_, i) => contract.methods.tasks(i + 1).call() ) ); setTask(tasks); }; // 修改createTask函数,监听receipt事件 const createTask = async (text) => { setLoading(true); try { await contract.methods.createTask(text) .send({ from: acct }) .once('receipt', async (receipt) => { console.log(`交易已上链,区块号: ${receipt.blockNumber}`); await loadTasks(); // 交易确认后刷新任务列表 setLoading(false); }) .on('error', (error) => { console.error(`交易失败: ${error}`); setLoading(false); }); } catch (error) { console.error(`创建任务出错: ${error}`); setLoading(false); } };
额外优化建议
- 监听钱包账户切换:如果用户切换钱包账户,需要重新加载链上数据,可添加账户切换监听:
useEffect(() => { loadBlockchainData(); // 监听账户切换事件 window.ethereum?.on('accountsChanged', (accounts) => { setAcct(accounts[0]); loadTasks(); // 切换账户后重新加载任务 }); // 组件卸载时移除监听 return () => { window.ethereum?.removeListener('accountsChanged', () => {}); }; }, []);
- 避免重复初始化:在
loadBlockchainData中,可判断contract是否已存在,跳过重复初始化逻辑。
关键说明
receipt事件:交易被打包进区块后触发,此时链上状态已完成更新,适合用来刷新数据。confirmation(n)事件:可指定交易被确认n次后触发(如confirmation(1)表示1次区块确认后),适合对安全性要求较高的场景。Promise.all批量获取:减少React状态更新次数,避免循环中多次调用setTask导致的状态异常。
内容的提问来源于stack exchange,提问作者mkmkmkmk
相关产品推荐
相关产品推荐

