I’ve tried to break this down to it’s simplest components to understand why the useEffect
in ButtonStatus
is not updating when the state of eventDataId
is updated in the processClickButton
function of the ButtonView
React Component. In this example, I’m making calls to ethereum’s smart contract on my local Ganache instance, and that is working fine and returning a vew eventDataId with each call.
The use case: a user clicks a button, handleButtonClick
fires off a request (in this case an ethereum smart contract call), and in the on()
function, we set the state of eventDataId
. I hoped this would then trigger the ButtonStatus
useEffect
by way of it’s dependencies array, specifically [eventDataId]
. I think this in turn should look up additional info and render the MintStatus
.
// I've removed all extraneous lines of code, for example the .catch() and .error() handlers on the contract.methods calls. import React, { useEffect, useState} from 'react'; const Web3 = require('web3'); const ButtonStatus = ({contract, account}) => { const [eventDataId, setEventDataId] = useState(); const [additionalData, setAdditionalData] = useState(); function retrieveAdditionalData(contract, account) { contract.methods.additionalData() .call({ from: account }) .then(function(res) { setAdditionalData(res); }); } useEffect(() => { retrieveAdditionalData(contract, account); }, [eventDataId]); return ( <div>Event Data Id is {eventDataId} with {additionalData}</div> ); } class ButtonView extends React.Component { constructor(props, context) { super(props, context); this.state = { eventDataId: undefined }; this.handleButtonClick = this.handleButtonClick.bind(this); } handleButtonClick() { const setState = this.setState.bind(this); const contract = this.props.contract; const account = this.props.account; contract.methods.doSomething() .send({ from: account }) .on('confirmation', function(confirmationNumber, receipt){ let eventDataId = receipt.events['Data Event'].returnValues.eventDataId; setState({ eventDataId: eventDataId }); }); } render() { return ( <button onClick={this.handleButtonClick}>Click Me</button> <ButtonStatus contract={this.props.contract} account={this.props.account} /> ); } } export default ButtonView;
I’m sure I’m missing some fundamental concept here. Does the behind-the-scenes “workings” of React{ useState }
even associate the eventDataId
state
value from ButtonView
to the state
value in ButtonStatus
. I suspect this is the where the trouble lies.
In short, I’m looking for help understanding how the response from contract.methods.doSomething().on(...)
can trigger the useEffect
of ButtonStatus
.
Advertisement
Answer
It seems you are wanting the useEffect
hook in ButtonStatus
to run when the eventDataId
state in the parent ButtonView
updates. When the state in the parent updates it will trigger a rerender, and thus rerender the child ButtonStatus
component. You can pass this.state.eventDataId
in as a prop to be used in the useEffect
‘s dependency array.
ButtonView
render() { return ( <button onClick={this.handleButtonClick}>Click Me</button> <ButtonStatus contract={this.props.contract} account={this.props.account} eventDataId={this.state.eventDataId} /> ); }
ButtonStatus
const ButtonStatus = ({ account, contract, eventDataId }) => { const [additionalData, setAdditionalData] = useState(); function retrieveAdditionalData(contract, account) { contract.methods.additionalData() .call({ from: account }) .then(function(res) { setAdditionalData(res); }); } useEffect(() => { retrieveAdditionalData(contract, account); }, [eventDataId]); return ( <div>Event Data Id is {eventDataId} with {additionalData}</div> ); }