wagmi icon indicating copy to clipboard operation
wagmi copied to clipboard

Hydrate component changes state while rendering, causing a react warning

Open h4l opened this issue 1 year ago • 2 comments

Describe the bug

The Hydrate component performs state mutations while rendering, which react detects and logs the https://reactjs.org/link/setstate-in-render warning/error.

Warning: Cannot update a component (App) while rendering a different component (Hydrate). To locate the bad setState() call inside Hydrate, follow the stack trace as described in https://reactjs.org/link/setstate-in-render at Hydrate (http://localhost:5173/node_modules/.vite/deps/wagmi.js?v=fdedff45:349:11) at WagmiProvider (http://localhost:5173/node_modules/.vite/deps/wagmi.js?v=fdedff45:373:11) at Root (http://localhost:5173/src/App.tsx?t=1708235152875:22:24)

image

Seems to originate here: https://github.com/wevm/wagmi/blob/main/packages/react/src/hydrate.ts#L21

For some reason Hydrate calls onMount() inside a useEffect in the server side, but not in a useEffect on the client side. I've not read through the code to understand why, but presumably this error wouldn't occur if the call was made from a useEffect.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/new-wagmi-judl71

Steps To Reproduce

  1. Open browser devtools
  2. Clear any unrelated warnings etc from initial page load
  3. Click the "Change Root State" button in the page
  4. Observe a React error in the console that Hydrate changed state while rendering

The Change Root State button here is triggering a render of the component that hosts Wagmi's context, which causes Hydrate to re-render and perform its state-change.

Note, sourcemaps don't seem to work in the stackblitz version, I made a repo here with the same that works locally: https://github.com/h4l/wagmi-impure-render-bug

Wagmi Version

2.5.7

Viem Version

2.7.10

TypeScript Version

5.3.3

Check existing issues

Anything else?

Can work around by hoisting the Wami context above any other contexts to prevent it re-rendering.

h4l avatar Feb 18 '24 06:02 h4l

mmm I'm not able to run Wagmi yet, but yep onMount should only be called once, so when the App component rerenders might cause this, regardless, rerendering your App component is usually bad practice because you're rerendering your whole application.

It shouldn't be called in a useEffect because the idea is to hydrate the store during page load, but should be called once

possible fix might be

  const active = useRef(true)
  
  // Hydrate for non-SSR
  if (!config._internal.ssr && active.current){
    onMount()
    active.current = false
  }

glitch-txs avatar Feb 18 '24 15:02 glitch-txs

Thanks. FWIW, when I triggered it, it was because I mistakenly had some state above the WagmiProvider which shouldn't/didn't need to be there.

h4l avatar Feb 18 '24 16:02 h4l

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.

github-actions[bot] avatar Apr 02 '24 00:04 github-actions[bot]