wevm / wagmi

Reactive primitives for Ethereum apps
https://wagmi.sh
MIT License
5.96k stars 1.05k forks source link

wagmi stays in the `reconnecting: true` state during the hot-reload #3490

Closed dalechyn closed 7 months ago

dalechyn commented 9 months ago

Describe the bug

When you're making any changes in nextjs routes, the app tries to hot reload and wagmi hands at the isReconnecting: true state:

https://github.com/wevm/wagmi/assets/35642018/fb6052dc-4a99-4cc4-82b3-97346213fcca

Link to Minimal Reproducible Example

https://github.com/dalechyn/mini-repros/tree/main/wagmi-hot-reload-infinite-reconnect

Steps To Reproduce

  1. pnpm dev
  2. Open src/app/revalidate/route.ts and make any change there
  3. Watch the connectors hang on hot-reload.

Wagmi Version

2.3.1

Viem Version

2.4.0

TypeScript Version

5.2.2

Check existing issues

Anything else?

Originally a similar bug (which I believe has a common root with issue) happened to me when I have used trpc's experimental app router library's revalidate method that revalidates a route by tag.

The same effect was achieved, yet I was not able to achieve the same effect with this repro outside of hot-reload, but when a revalidation happens from the server-side, wagmi suffers from the same reconnect hanging issue:

https://github.com/wevm/wagmi/assets/35642018/bf281c8e-4046-4a68-97e1-54cecc6cba69

Reference scrapped out code:

  const { address, isConnecting, isReconnecting, isConnected } = useAccount()

  const skeleton = (
    <Button {...rest} disabled>
      <Loader className="mr-1 w-4 h-4 animate-spin stroke-foreground" />
      Tip
    </Button>
  )

  if (isConnecting || isReconnecting)
    return (
      <>
        {skeleton}isConnecting: {isConnecting.toString()}isReconnecting:{' '}
        {isReconnecting.toString()}
      </>
    )
  if (!isConnected || !address) return <ConnectButton />

  return (
    <Suspense
      fallback={
        <>
          {skeleton}
          Suspense
        </>
      }
    >
      <Something />
    </Suspense>
  )
keagancoding commented 9 months ago

Any luck with this im getting a smiliar error where I have to reconnect my wallet every hot reload?

dalechyn commented 9 months ago

I've debugged a little bit and think that the issue is that the onMount is not being triggered because the active ref stays with value { current: false } on re-render, and because useEffect's dependencies don't change, therefore the onMount function is never called to hydrate wagmi.

I'm not that great in wagmi's codebase but I suppose that some connector-related state is being forcefully purged when it in fact should not be, and the onMount shouldn't even theoretically be called because the state should not have been purged therefore should not need a hydration.

https://github.com/wevm/wagmi/assets/35642018/57dacc3f-b420-4802-8439-b8cbe148d87f

https://github.com/wevm/wagmi/blob/ace8acfa314a4a91bca911d252ba396ede0615f9/packages/react/src/hydrate.ts#L12-L36

dalechyn commented 9 months ago

Any luck with this im getting a smiliar error where I have to reconnect my wallet every hot reload?

Your issue is a bit different I believe, make sure you're persisting wagmi state via cookies https://wagmi.sh/react/guides/ssr#persistence-using-cookies

dalechyn commented 9 months ago

I was able to modify the script the next way and now onMount is called on hot-reload.


 export function Hydrate(parameters: React.PropsWithChildren<HydrateProps>) { 
   const { children, config, initialState, reconnectOnMount = true } = parameters 

   const { onMount } = hydrate(config, { 
     initialState, 
     reconnectOnMount, 
   }) 

   // Hydrate for non-SSR 
   if (!config._internal.ssr) onMount() 

   // biome-ignore lint/nursery/useExhaustiveDependencies: 
   useEffect(() => { 
     if (!config._internal.ssr) return 
     onMount() 
   }, [onMount]) 

   return children as ReactElement 
 } 

As far as I've understood, the cont active = useRef(true) was there to really make sure the effect is run just once as React doesn't guarantee that an effect won't be re-run once again, yet for the same reason the dependencies were empty to minimize the redundant effect calls.

However, I think the effect still has to be run as during hot-reload component might get re-mounted.

Using this as a workaround for now.

dalechyn commented 9 months ago

#3492 also fixes revalidate rerender issue that was mentioned in the "Anything else?" block.

smauret commented 7 months ago

Hello, I'm getting that behaviour too, trying to do a web3 action after hot reload fails with TypeError: connection.connector.getProvider is not a function, do we know when this can be fixed ?

kiknaio commented 7 months ago

Hello, I'm getting that behaviour too, trying to do a web3 action after hot reload fails with TypeError: connection.connector.getProvider is not a function, do we know when this can be fixed ?

I have exactly same issue. Have you fixed it?

github-actions[bot] commented 6 months ago

This issue has been locked since it has been closed for more than 14 days.

If you found a concrete bug or regression related to it, please open a new bug report with a reproduction against the latest wagmi version. If you have any other comments you can create a new discussion.