在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的主要内容,如果未能解决你的问题,请参考以下文章