React新手求助:如何稳定渲染区块链与IPFS的动态表格数据?
问题诊断与修复方案
核心问题
你的代码存在两个关键问题导致数据渲染不稳定:
applicationNumberArray.map(async ...)中的异步函数不会被等待,listOfApplication经常在所有请求完成前就被传入setDataTable;硬编码的setTimeout(3000)完全依赖网络运气,网络延迟高时数据还没返回就更新了状态。- 使用全局变量
applicationContract、metamaskAddress、applicationNumberArray,组件重渲染时容易引发竞态,导致数据混乱。
修复后的完整代码
import { useState, useEffect } from "react"; import { useLoaderData } from "react-router-dom"; import Table from "../components/Table"; import { Buffer } from 'buffer'; import getHashFromIPFS from "../services/getHashFromIPFS"; function ViewApplication() { const { fetchBlockchainData } = useLoaderData(); const [dataTable, setDataTable] = useState([]); const [isLoading, setIsLoading] = useState(true); // 新增加载状态 // 变量移至组件内部,避免全局竞态 const metamaskAddress = fetchBlockchainData[0]; const applicationContract = fetchBlockchainData[2]; useEffect(() => { const fetchData = async () => { try { // Step 1: 获取用户的申请编号列表 const applicationNumberArray = await applicationContract.methods.getUserApplication(metamaskAddress).call(); // Step 2: 用Promise.all等待所有详情请求完成 const listOfApplication = await Promise.all( applicationNumberArray.map(async (appno) => getApplicationDetails(appno)) ); // Step 3: 所有数据就绪后再更新状态 setDataTable(listOfApplication); } catch (err) { console.error('数据获取失败:', err); } finally { setIsLoading(false); } }; fetchData(); }, [metamaskAddress, applicationContract]); // 添加依赖项,符合hooks规则 // 优化异步函数写法,消除嵌套then const getApplicationDetails = async (appno) => { const AppDataHash = await applicationContract.methods.getApplicationData(appno).call(); const getData = await getHashFromIPFS(AppDataHash); return JSON.parse(Buffer.from(getData.value.buffer).toString()); }; // 加载状态提示 if (isLoading) { return <div>加载中...</div>; } // 空数据提示 if (dataTable.length === 0) { return <div>暂无申请记录</div>; } // 表格配置 const config = [ { label: 'Application No.', render: (data) => data.applicationno }, { label: 'Name', render: (data) => data.name }, { label: 'Status', render: (data) => data.status }, { label: '', render: (data) => <>View More</> } ]; const keyFn = (data) => data.applicationno; return <Table data={dataTable} config={config} keyFn={keyFn} />; } export default ViewApplication;
关键修改说明
- 用
Promise.all替代map+setTimeout:确保所有IPFS数据请求完成后再一次性更新状态,彻底解决数据缺失问题。 - 移除全局变量:将变量移至组件内部,避免组件重渲染时的全局状态污染。
- 优化异步逻辑:把
getApplicationDetails改成纯async/await形式,消除嵌套then,代码更易读且便于调试。 - 添加状态提示:新增加载状态和空数据提示,避免页面空白,提升用户体验。
- 完善依赖数组:给
useEffect添加正确的依赖项,符合React Hooks规则,避免无效渲染。
内容的提问来源于stack exchange,提问作者Niana
相关产品推荐
相关产品推荐

