在solidity合约实例承诺中反应setState

Posted

技术标签:

【中文标题】在solidity合约实例承诺中反应setState【英文标题】:React setState inside solidity contract instance promises 【发布时间】:2018-04-13 09:55:44 【问题描述】:

我在本地 testrpc 区块链上部署了一个可靠合约。我所有的合约方法测试都已检出,但处理 Web3 事务并相应地更新状态给我带来了麻烦。

当我添加一个用户帐户时,我的下一个操作是返回我的合同的所有用户帐户。以及...更新我的状态(RegisteredAccounts)。 但是,通过我的一系列承诺,我没有看到我的状态更新。我知道 setState 也是异步的,所以如何在不刷新页面或调用 ComponentDidMount() 的情况下查看我的状态更新?

这是我的 Solidity Accounts 合同(我目前处理的部分

pragma solidity ^ 0.4.4;
contract Accounts 

  mapping(address => User) public mUsers;
  address[] public Users; //users whitepages

  struct User 
    string handle;
    bytes32[] taskList;
  

  function addNewUser(string _handle) returns(bool success) 
    address newUserAddr = msg.sender;

    //if handle not in userAddresses & the handle is not null
    if (bytes(mUsers[newUserAddr].handle).length == 0 && bytes(_handle).length != 0) 
      mUsers[newUserAddr].handle = _handle;
      Users.push(newUserAddr);
      return true;
     else 
      return false;
    
  

  function getUsers() constant returns(address[]) 
    return Users;
  

这是我的 App 容器组件——相关部分 registerNewUser() 现在是我的问题孩子。

class App extends Component 
  state = 
    modalOpen: false,
    SenderAddress: null,
    RegisteredAccounts: [],
    isRegisteredUser: false,
    SenderTaskList: [], //not set
    AccountsCtrct: null,
    web3: null
  
  //#region APP METHODS
  componentWillMount() 
    // Get network provider and web3 instance. -- See utils/getWeb3 for more info.
    getWeb3.then(results => 
      this.setState(
        web3: results.web3
      )
      this.instantiateContracts() //instantiate contract
    ).catch(() => 
      console.log('Error finding web3.')
    )
  


  instantiateContracts() 
    this.setState(
      AccountsCtrct: contract(AccountsContract)
    )
    this.state.AccountsCtrct.setProvider(this.state.web3.currentProvider)

    //Get block chain addresses --- only returns the current address selected in metamask (web3 current addr)
    this.state.web3.eth.getAccounts((error, accounts) => 
      this.setState(
        SenderAddress: accounts[0]
      )

      //INIT ACCOUNTS CONTRACT
      var acctDeployed = this.state.AccountsCtrct.deployed()
      acctDeployed.then((instance) => 
        return instance.getUsers();
      ).then((res) => 
        this.setState(
          RegisteredAccounts: res
        )

        if (this.state.RegisteredAccounts.includes(this.state.SenderAddress)) 
          this.setState(
            isRegisteredUser: true
          )
        
      )
    )
  


  registerUser = (handle) => 
    var acctInstance
    this.state.AccountsCtrct.deployed().then((inst) => 

      //add current user to this account
      acctInstance = inst
      return acctInstance.addNewUser(handle, 
        from: this.state.SenderAddress
      );
    ).then(() => 

      //now we added our user -- update registeredAccounts setState
      //pass response users array to promise
      return acctInstance.getUsers()
    ).then(res => 

      this.setState(
        RegisteredAccounts: res
      )
      if (res.includes(this.state.SenderAddress)) 
        this.setState(
          isRegisteredUser: true
        )
      
    )
  

  toggleModal = () => 
    this.setState(prevState => (
      modalOpen: !prevState.modalOpen
    ));
  
  //#endregion
  
  render() 
    return (
      <div className="App">
        <nav className="navbar pure-menu pure-menu-horizontal">
            <a href="#" className="pure-menu-heading pure-menu-link">Truffle Box</a>
            
              !this.state.isRegisteredUser
              ? <a style=navLink onClick= this.toggleModal  href="#" className="pure-menu-heading pure-menu-link">Register</a>
              : null
            
        </nav>

        <ModalUserNav visible=this.state.modalOpen
              toggleModal=this.toggleModal
              isRegistered=this.state.isRegisteredUser
              registerUser=this.registerUser />
    );
  

Last my Child 组件

class ModalUserNav extends Component 
  state = 
    unpl: "UserName",
    pwpl: "Password",
    errorCode: 'Registration Failed',
    errorVisible: false
  


  handleOnChangePL = (e) => 
    this.setState(
      [e.target.name]: e.target.value
    )
  

  handleSubmit = () => 
    if (this.state.unpl !== "") 
      this.props.registerUser(this.state.unpl)
      this.props.toggleModal();
     else 
      //if the input is empty update the error code and show
      console.log('registration failed!')
      this.setState(
        errorCode: 'REGISTRATION ERR: empty handles are not allowed!',
        errorVisible: true
      )
    
  

  render() 
    return (
      <section>
          <Modal visible=this.props.visible effect="fadeInUp">
            <div className="pure-form">
              <fieldset style=modalFormView>
                <legend style=fontSize: "18px"><b>Register now. All you need is a handle!</b></legend>
                <div className="flexContainer">
                  <input style=marginTop: "7px", height: "2.6em", marginLeft: "5px", marginRight: "5px" type="text" name="unpl" placeholder=this.state.unpl onChange=(event) => this.handleOnChangePL(event) value=this.state.unpl />
                  <button style=btnStyle type="submit" className="pure-button pure-button-primary" onClick=() => this.handleSubmit()><b>Register</b></button>
                </div>
              </fieldset>
            </div>
          </Modal>
      </section>
    )
  

简而言之,我想用 setState 跟踪我的 2 个异步任务(addNewUser、getUsers),这样我就可以自动更改我的 UI 而无需刷新。那么我做错了什么?请严厉...我需要知道。

谢谢!

【问题讨论】:

【参考方案1】:

您应该将instantiateContracts 移动到setState,因为setState 不会立即更新数据。 https://reactjs.org/docs/react-component.html#setstate

  this.setState(
    web3: results.web3
  , () => 
    this.instantiateContracts() //instantiate contract
  )

更新1:关于registerUser:应该是

  this.setState(
    RegisteredAccounts: res
  , () => 
    if (res.includes(this.state.SenderAddress)) 
      this.setState(
        isRegisteredUser: true
      )
    
  )

【讨论】:

注意!谢谢你的提示我已经改变了一点。对我的 registerUser 方法有什么建议吗?完成后甚至可以更新我的用户界面吗?或任何 setState 的侦听器更新排队 UI 更新的数据?

以上是关于在solidity合约实例承诺中反应setState的主要内容,如果未能解决你的问题,请参考以下文章

solidity语法4——合约(类似面向对象中的Class)

solidity开发以太坊代币智能合约

Solidity零基础入门Solidity编写智能合约代码

Solidity零基础入门Solidity编写智能合约代码

Solidity零基础入门Solidity编写智能合约代码

Solidity零基础入门Solidity编写智能合约代码