Using “React Query” to query smart contracts (part 2)
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.
Custom hook
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 paused()
value:
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 _pause()
and _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 Paused
and 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: queryClient
and 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 useMemo
.
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 usePaused
adds queryKey
to the returned object so that callers may use it to invalidate cache anywhere else if required.
Previous: Using “React Query” to query smart contracts (part 1)
Next: Using “React Query” to query smart contracts (part 3)