有人可以向我解释为什么这里的道具为空吗? 我使用 HOC 来隔离连接到 web3 和区块链的逻辑。
当我的应用程序组件被包裹在 hoc 中时,道具存在(web3、contract ....) 但是,当我需要在函数 setStatusWorkflow 中访问它时,它为 null。怎么来的?
import React, { useEffect, useMemo, useState } from "react";
import VotingContract from "./contracts/Voting.json";
import getWeb3 from "./getWeb3";
import "./App.css";
const Toast = ({ visibility }) => {
return (
<div className="position-fixed bottom-0 end-0 p-3" style={{ zIndex: 5 }}>
<div id="liveToast" className={`toast ${visibility}`} role="alert" aria-live="assertive" aria-atomic="true">
<div className="toast-header d-flex justify-content-between">
<small>just now</small>
<button type="button" className="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div className="toast-body">
✅ New voter added
</div>
</div>
</div>
)
}
const withContract = Component => () => {
const [state, setState] = useState({
storageValue: 0,
web3: null,
accounts: null,
contract: null,
winningProposalId: null,
voters: [],
admin: '',
})
const connectWeb3 = new Promise(async (resolve) => {
const web3 = await getWeb3();
resolve(web3)
});
const connectBlockchain = (web3) => new Promise(async (resolve) => {
const accounts = await web3.eth.getAccounts();
const networkId = await web3.eth.net.getId();
const deployedNetwork = VotingContract.networks[networkId];
const instance = new web3.eth.Contract(
VotingContract.abi,
deployedNetwork && deployedNetwork.address,
);
console.log('connected to blockchain')
resolve({ web3, instance, accounts })
})
useEffect(() => {
connectWeb3
.then(connectBlockchain, console.error)
.then(({ web3, instance, accounts }) => {
setState({ web3, accounts, contract: instance, admin: accounts[0] })
})
}, [])
return <Component {...state} />
}
const App = ({ contract, accounts, admin }) => {
const statusArray = ["RegisteringVoters", "ProposalsRegistrationStarted", "ProposalsRegistrationEnded", "VotingSessionStarted", "VotingSessionEnded", "VotesTallied"];
const [state, setState] = useState({
storageValue: 0,
winningProposalId: null,
voters: [],
admin: '',
})
const [status, setStatus] = useState("")
const [visible, setVisible] = useState(false)
const visibility = useMemo(() => visible ? 'show' : 'hide', [visible])
const displayToast = (event) => {
console.log(event)
setVisible(true)
setTimeout(() => setVisible(false), 4000);
}
const setStatusWorkflow = () => new Promise(async (resolve) => {
const status = await contract.methods.status().call();
setStatus(statusArray[status])
resolve(contract)
});
const subscribeEvents = () => new Promise(async (resolve) => {
contract.events.WorkflowStatusChange({})
.on('data', console.log)
.on('error', console.error)
contract.events.VoterRegistered('0xe5f117D1A8E114B9a47d1a6490b81c85F8124E6E')
.on('data', displayToast)
.on('error', console.error)
});
const startProposalRegistration = async () => {
try {
await contract.methods.startProposalRegistration().send({ from: state.admin });
setStatusWorkflow();
} catch (err) {
console.log(err)
}
}
const endProposalRegistration = async () => {
try {
await contract.methods.endProposalRegistration().send({ from: state.admin });
setStatusWorkflow();
} catch (err) {
console.log(err)
}
}
const addVoter = async () => {
const { contract } = state;
try {
await contract.methods.addVoter('0xe5f117D1A8E114B9a47d1a6490b81c85F8124E6E').send({ from: state.admin });
} catch (err) {
console.log(err)
}
}
useEffect(() => {
(async () => {
await setStatusWorkflow();
await subscribeEvents()
})()
}, [contract])
return (
<div className="App">
{!state.contract && <div>Loading Web3, accounts, and contract...</div>}
{state.contract &&
<>
<Toast visibility={visibility} />
<h1>Contract Voting!</h1>
<ul>
<li>Administrateur du contract (owner) : {state.admin}</li>
<li>Contract's address : {state.contract.options.address}</li>
<h2>Status du vote : {status}</h2>
</ul>
<button onClick={addVoter}>Add new Voter</button>
{(status === "ProposalsRegistrationEnded" || status === "RegisteringVoters") && <button onClick={startProposalRegistration}>Start Proposal</button>}
{status === "ProposalsRegistrationStarted" && <button onClick={endProposalRegistration}>End Proposal</button>}
</>
}
</div>
);
}
export default withContract(App)