coral-xyz / backpack

🎒 Next level crypto wallet
https://backpack.app
GNU General Public License v3.0
1.38k stars 822 forks source link

window.xnft.publicKeysUpdate event not being emitted #3347

Closed mcintyre94 closed 1 year ago

mcintyre94 commented 1 year ago

The usePublicKeys hook in the quickstart relies on an emitted publicKeysUpdate event (https://github.com/coral-xyz/xnft-quickstart/blob/master/src/hooks/xnft-hooks.tsx#L24):

    window.xnft.on("publicKeysUpdate", () => {
      setPublicKeys(window.xnft.publicKeys);
    });

This event doesn't seem to be emitted when window.xnft.publicKeys transitions from undefined to being set

You can see this by using this modified hook:

export function usePublicKeys(): PublicKey {
  const [publicKeys, setPublicKeys] = useState(window.xnft.publicKeys);
  console.log('upk initial state', publicKeys)
  useEffect(() => {
    window.xnft.on("publicKeysUpdate", () => {
      console.log('upk publicKeysUpdate', window.xnft.publicKeys)
      setPublicKeys(window.xnft.publicKeys);
    });

    setTimeout(() => {
      console.log('after the timeout...', window.xnft.publicKeys)
      setPublicKeys(window.xnft.publicKeys);
    }, 5000);
  }, [setPublicKeys]);
  return publicKeys;
}

In addition to the existing event listener, this adds a check of window.xnft.publicKeys 5s after load, and also adds some debug logging

When I run an xnft calling this hook I see in the console:

upk initial state undefined
(5 seconds later)
after the timeout... {solana: '7YKyMZdjoerS4ceCQivrMm6akpFhVMXLhwa3MC7ez6bA'}

In an app displaying the result of this hook I can also see that the value doesn't update before the timeout after 5s

So the window.xnft.publicKeys is correctly updating, but the event handler window.xnft.on("publicKeysUpdate", ... is not being called. My best guess is that this is a bug in backpack where the event is not being emitted correctly

Tested on the current latest build, 0.5.2-latest-4128

ph101pp commented 1 year ago

I think the event behaviour is correct, update events fire on update and not on initial set. There is a connect event which includes initial data and ensures window.xnft is available and functional.

The problem here is that most of the hooks dont wait for the connect event to make sure initial values are set iE window.xnft.publicKeys.

So instead of a timeout the hook should listen to the connect event:

export function usePublicKeys(): PublicKey {
  const [publicKeys, setPublicKeys] = useState(window.xnft.publicKeys);
  console.log('upk initial state', publicKeys)
  useEffect(() => {
    window.xnft.on("publicKeysUpdate", () => {
      setPublicKeys(window.xnft.publicKeys);
    });

    window.xnft.on("connect", () => {
      setPublicKeys(window.xnft.publicKeys);
    });
  }, [setPublicKeys]);
  return publicKeys;
}
ph101pp commented 1 year ago

Updated hooks here: https://github.com/coral-xyz/xnft-quickstart/pull/33