apibara / starknet-react

A collection of React providers and hooks for StarkNet
https://starknet-react.com
MIT License
365 stars 146 forks source link

`useStarknetCall` breaks if `useContract` is called before starknet provider loaded #101

Closed Pet3ris closed 2 years ago

Pet3ris commented 2 years ago

Problem

I ran into the following situation:

I have some code that invokes the useStarknetCall hook right after the useContract hook.

let useContractParams = ReactStarknet.UseContract.Parameters.make(
  ~abi=Abi.taskRegistry,
  ~address=registryAddress,
  ()
)
let {contract} = ReactStarknet.useContract(useContractParams)
let useStarknetCallParams = ReactStarknet.UseStarknetCall.Parameters.make(
  ~contract=contract -> Belt.Option.getWithDefault(%raw("undefined")), 
  ~method="invocations",
  ~args=[task.int_address],
  ()
)
let {data, loading, error, refresh} = ReactStarknet.useStarknetCall(useStarknetCallParams)

There's no real magic in this code as it translates to the following JS:

var match = Core.useContract(useContractParams);
var contract = match.contract;
var useStarknetCallParams = {
  contract: Belt_Option.getWithDefault(contract, undefined),
  method: "invocations",
  args: [task.int_address]
};
var match$1 = Core.useStarknetCall(useStarknetCallParams);

I noticed an issue where if the contract is not yet loaded when the useCallback is called inside of the useStarknetCall hook, then the hook never refreshes it's call to StarkNet.

I had to add the following hook to the code to make it work and make the address compose:

Shortcut fix

React.useEffect1(() => {
  if Belt.Option.isSome(contract) {
    refresh()
  }

  None
}, [contract])

Which translates to the following JS:

var refresh = match$1.refresh;
React.useEffect((function () {
        if (Belt_Option.isSome(contract)) {
          Curry._1(refresh, undefined);
        }

      }), [contract]);

Possible fix

I wonder if it's important enough given useContract and useStarknetCall would typically be called in this sequence, to bake this logic or some form of it into the hook itself.

I can see that this issue does not arise during in the demo program despite the hooks being called in short succession.

NOTE When I use the trick above, there are still some wasted requests that get created without a contract_address being specified (this may be a starknet.js issue also).

fracek commented 2 years ago

I will look into this. It's pretty cool how your effort to bind this library to Rescript is uncovering a lot of issues.

Pet3ris commented 2 years ago

Have some additional information: this error does not occur when issuing calls before ArgentX is connected. It only occurs once the wallet is connected => then there are a couple of failed requests.

Pet3ris commented 2 years ago

Version mismatch 🤦‍♂️. Had to write my own hook to nail down underlying issue (contract.connectedTo got changed to contract.address in starknet.js) but all good now.