【问题标题】:React setState inside solidity contract instance promises在solidity合约实例承诺中反应setState
【发布时间】: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 而无需刷新。那么我做错了什么?请严厉...我需要知道。

谢谢!

【问题讨论】:

    标签: javascript reactjs contract setstate web3


    【解决方案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 更新的数据?
    猜你喜欢
    • 2018-01-03
    • 2017-08-19
    • 1970-01-01
    • 2018-06-02
    • 2020-12-14
    • 2019-05-09
    • 2017-07-07
    • 2019-04-23
    • 1970-01-01
    相关资源
    最近更新 更多