1. 环境搭建
如果对truffle react box的环境部署不熟请移步
https://blog.csdn.net/oulingcai/article/details/85088967
2. solidity合约
pragma solidity ^0.4.24;
contract Voting {
//候选人
string[] public candidates=new string[](0);
//票数
mapping(string=>uint) ballots;
constructor() public{
}
//是否在候选人中
function checkCandidate(string _candidate) public view returns(bool){
for(uint i=0; i<candidates.length; i++){
if(hashCompareInternal(candidates[i],_candidate)){
return true;
}
}
return false;
}
//投票
function vote(string _candidate) public{
assert(checkCandidate(_candidate));
ballots[_candidate]+=1;
}
//得到票数
function getBallot(string _candidate) public view returns(uint){
assert(checkCandidate(_candidate));
return ballots[_candidate];
}
//得到候选人个数
function getCandidatesCount() public view returns(uint){
return candidates.length;
}
//对比两个string是否相等
function hashCompareInternal(string a, string b) pure private returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
//添加候选人
function addCandidate(string _person) public{
if(checkCandidate(_person)){
return;
}else{
candidates.push(_person);
}
}
//得到候选人名称
function getCandidates(uint index) view public returns(string){
return candidates[index];
}
}
3. react
3.1 state字段
state = { storageValue: 0, candidates:[], web3: null, accounts: null, contract: null };
3.2 得到合约对象和用户钱包地址
componentDidMount = async () => {
try {
// Get network provider and web3 instance.
const web3 = await getWeb3();
// Use web3 to get the user's accounts.
const accounts = await web3.eth.getAccounts();
// Get the contract instance.
const Contract = truffleContract(Voting);
Contract.setProvider(web3.currentProvider);
//得到合约对象
const instance = await Contract.at("0xd3a404902012f84dc625e8de00c02f1648a5bfad");
// Set web3, accounts, and contract to the state, and then proceed with an
// example of interacting with the contract's methods.
this.setState({ web3, accounts, contract: instance }, this.runExample);
} catch (error) {
// Catch any errors for any of the above operations.
alert(
`Failed to load web3, accounts, or contract. Check console for details.`
);
console.log(error);
}
};
3.3 查询目前投票的信息
render() {
//渲染器
if (!this.state.web3) {
return <div>Loading Web3, accounts, and contract...</div>;
}
return (
<div className="App">
<h1>Good to Go!</h1>
<h1>当前候选人{this.state.storageValue}个</h1>
<ul>{
this.state.candidates.map((person,i)=>{
return <li key={i}>候选人: {person.name} 当前票数:{person.count}
<button onClick={async ()=>{
const {candidates,accounts,contract } = this.state;
//调用合约 投票
await contract.vote(person.name,{from:accounts[0]});
let response=await contract.getBallot(person.name);
candidates[i].count=response.toNumber();
this.setState({candidates: candidates});
}}>投票</button></li>
})
}
</ul>
<input ref="candidateName" style={{width:200,height:20}}></input>
<button onClick={async ()=>{
let value=this.refs.candidateName.value;
const {storageValue,candidates,accounts,contract } = this.state;
console.log(value+"===="+candidates.length);
//调用合约 添加候选人
await contract.addCandidate(value,{from:accounts[0]});
var element={name:value,count:0};
candidates[candidates.length]=element;
this.setState({storageValue: storageValue+1,candidates: candidates});
}}>添加候选人</button>
</div>
);
}
}
3.5 完整代码
import React, { Component } from "react";
import Voting from "./contracts/Voting.json";
import getWeb3 from "./utils/getWeb3";
import truffleContract from "truffle-contract";
import "./App.css";
class App extends Component {
state = { storageValue: 0, candidates:[], web3: null, accounts: null, contract: null };
componentDidMount = async () => {
try {
// Get network provider and web3 instance.
const web3 = await getWeb3();
// Use web3 to get the user's accounts.
const accounts = await web3.eth.getAccounts();
// Get the contract instance.
const Contract = truffleContract(Voting);
Contract.setProvider(web3.currentProvider);
//得到合约对象
const instance = await Contract.at("0xd3a404902012f84dc625e8de00c02f1648a5bfad");
// Set web3, accounts, and contract to the state, and then proceed with an
// example of interacting with the contract's methods.
this.setState({ web3, accounts, contract: instance }, this.runExample);
} catch (error) {
// Catch any errors for any of the above operations.
alert(
`Failed to load web3, accounts, or contract. Check console for details.`
);
console.log(error);
}
};
runExample = async () => {
const { accounts,candidates,contract } = this.state;
const response=await contract.getCandidatesCount();
console.log(response.toNumber());
//得到投票信息,注意,这里每个候选人都要查询区块,效率太低,真正项目不能这么做,要一次性返回所以信息
for (var i = 0; i < response.toNumber(); i++) {
// 候选人名字和票数的结构体
var element={name:"",count:0};
element.name=await contract.getCandidates(i);
let response=await contract.getBallot(element.name);
element.count=response.toNumber();
candidates[i]=element;
console.log(candidates[i]);
}
this.setState({ storageValue: response.toNumber(),candidates: candidates});
};
render() {
//渲染器
if (!this.state.web3) {
return <div>Loading Web3, accounts, and contract...</div>;
}
return (
<div className="App">
<h1>Good to Go!</h1>
<h1>当前候选人{this.state.storageValue}个</h1>
<ul>{
this.state.candidates.map((person,i)=>{
return <li key={i}>候选人: {person.name} 当前票数:{person.count}
<button onClick={async ()=>{
const {candidates,accounts,contract } = this.state;
//调用合约 投票
await contract.vote(person.name,{from:accounts[0]});
let response=await contract.getBallot(person.name);
candidates[i].count=response.toNumber();
this.setState({candidates: candidates});
}}>投票</button></li>
})
}
</ul>
<input ref="candidateName" style={{width:200,height:20}}></input>
<button onClick={async ()=>{
let value=this.refs.candidateName.value;
const {storageValue,candidates,accounts,contract } = this.state;
console.log(value+"===="+candidates.length);
//调用合约 添加候选人
await contract.addCandidate(value,{from:accounts[0]});
var element={name:value,count:0};
candidates[candidates.length]=element;
this.setState({storageValue: storageValue+1,candidates: candidates});
}}>添加候选人</button>
</div>
);
}
}
}
}
export default App;