In my previous post I explained how
useQuery can be used to retrieve the value from an immutable method. Now let’s go up a notch and see how to use on methods where the returned value may change over time.
NOTE: This series of articles use TypeChain to make strongly-typed calls to Ethereum. Please check its documentation and discussion board to learn how to set it up. It’s also assumed some knowledge of React Query.
Let’s say that our
MyToken smart contract derives from OpenZeppelin’s
Pausable. This means
MyToken has a
paused() public method that returns a
bool. Based on the previous post, we can implement the following to retrieve
Notice that the parameter
contract is of type
Pausable. This allows this hook to be used for any contract that derives from
Pausable. Calling the hook can look something like this:
Notice in the
useQuery options that the
initialData is set to
true. This value is added to the cache before the first call. It’s safer to assume that the contract is paused than assuming by default that it’s unpaused.
Making it reactive
Pausable has internal methods
_unpause() that change the value returned by
paused(). These methods would be exposed as public methods on
MyToken with restricted access to an admin account. Using the
usePaused hook implementation from above, we would have to refresh the page to find the changes caused by these two methods. Fortunately there’s a way to fix this issue.
Pausable emits the events
Unpaused when their respective methods succeed. TypeChain generates the required code to register and unregister callbacks for these events. It can be used as follow:
We can use these callbacks to invalidate the cache in
usePaused. To do that we’ll have to add the following:
We are using a
useEffect that registers the callbacks and returns a lambda that unregisters them.
Both callbacks call a
onPausedChange method. This method performs an optimistic update, meaning that it sets the value in the cache even before the retrieve call is performed.
Unfortunately the event handler is called multiple times when the event is emitted. That’s not a big issue in this case but take it into considerations when adding and removing elements from a collection.
The code inside
onPausedChange needs two additional values:
queryKey. For the
queryClient, we can use the value returned by
useQueryClient. For the
queryKey, we have to use the same value as it’s passed to
useQuery. As the
queryKey value varies with the contract address, we should use a
Putting it all together will look like this:
Using this custom hook, the value of
paused automatically changes when it changes on the smart contract. This allows for your app to be fully reactive.
This last version of
queryKey to the returned object so that callers may use it to invalidate cache anywhere else if required.