Frontend: React(初学者)后端:区块链,IPFS,Node js
使用IPFS存储应用程序的详细信息(大数据)和将用户的哈希值保存在区块链(智能合约)中,用户的应用程序编号列表以数组的形式存储在区块链中。
在react中使用数组从后端(从区块链和IPFS)渲染应用程序细节,但渲染动态数据存在问题。一些数据丢失,而显示在表组件在反应或重新加载页面后几次完整的数据获取和表组件上显示。使用多个函数获取数据
在表上查看的动态数据,但在表组件上查看的数据在重新加载页面时或多或少显示。
import { useState, useEffect } from "react";
import { useLoaderData, Link } from "react-router-dom";
import Table from "../components/Table";
import { Buffer } from 'buffer';
import getHashFromIPFS from "../services/getHashFromIPFS";
let applicationContract, metamaskAddress;
let applicationNumberArray;
function ViewApplication() {//Functional Component
const { fetchBlockchainData } = useLoaderData(); //Fetch metamask wallet and contracts
const [dataTable, setDataTable] = useState([]); //array to set dynamic data
metamaskAddress = fetchBlockchainData[0];
applicationContract = fetchBlockchainData[2];
useEffect(() => {
fetchData() // Function 1
.then((res) => {
console.log('res')
console.log(res)
})
.catch(err => console.log(err))
}, [])
const fetchData = async () => {
let appArray = []
let listOfApplication = []
// Step 1 : Fetch list of application(application number) of a user from Blockchain
applicationNumberArray = await applicationContract.methods.getUserApplication(metamaskAddress).call();
// Step 2 : Fetch application details(ipfs hash) for each application number
applicationNumberArray.map(async (applicationNumber) => {
await getApplicationDetails(applicationNumber) // Function 2
.then((result) => {
//tried to set data here but react component re-render in loop
// setDataTable(result)
listOfApplication.push(result)
})
})
setTimeout(() => {
//Step 5: Set state variable each time data returned
setDataTable(listOfApplication)
}, 3000)
}
const getApplicationDetails = (appno) => {
return new Promise(async (res, rej) => {
//Step 3 : Get Ipfs hash for each application from Blockchain
await applicationContract.methods.getApplicationData(appno).call().then(async (AppDataHash) => {
//Step 4 : Extract ipfs hash and return its data
await getHashFromIPFS(AppDataHash).then((getData) => {
let ipfsConverted = JSON.parse(Buffer.from(getData.value.buffer).toString());
let application = [];
application = ipfsConverted;
res(application);
});
});
});
}
//Step 6 Set dynamic data to reusable table component
let data = dataTable;
if (data.length > 0) {
const config = [
{ label: 'Application No.', render: (data) => data.applicationno },
{ label: 'Name', render: (data) => data.name, },
{ label: 'Status', render: (data) => data.status, },
{ label: '', render: (data) => <><button>View More</button></> }
];
const keyFn = (data) => {
return data.applicationno;
};
return (
<>
<Table data={data} config={config} keyFn={keyFn} />
</>
)
}
}
你没有等待所有的承诺完成。
你可以通过提升组件本身之外的数据获取来简化你的代码(并通过使用async
/await
而不是new Promise
反模式):
async function getApplicationDetails(applicationContract, appno) {
const appDataHash = await applicationContract.methods.getApplicationData(appno).call();
const ipfsData = await getHashFromIPFS(appDataHash);
return JSON.parse(Buffer.from(ipfsData.value.buffer).toString());
}
async function getApplicationsData(applicationContract, metamaskAddress) {
const applicationNumberArray = await applicationContract.methods.getUserApplication(metamaskAddress).call();
// Fires off the promises...
const applicationPromises = applicationNumberArray.map((appNo) => getApplicationDetails(applicationContract, appNo));
// ... waits for them to finish and gathers the data.
return await Promise.all(applicationPromises);
}
function ViewApplication() {
const { fetchBlockchainData } = useLoaderData();
const [dataTable, setDataTable] = useState(null);
const metamaskAddress = fetchBlockchainData[0];
const applicationContract = fetchBlockchainData[2];
useEffect(() => {
if (!(metamaskAddress && applicationContract)) return;
getApplicationsData(applicationContract, metamaskAddress)
.then((res) => setDataTable(res))
.catch((err) => console.log(err));
}, [applicationContract, metamaskAddress]);
if (dataTable === null) return <div>Loading...</div>;
// ... render using dataTable...
}