1. 程式人生 > >基於truffle react box的投票demo

基於truffle react box的投票demo

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;

4 效果

在這裡插入圖片描述