welldone-software / why-did-you-render

why-did-you-render by Welldone Software monkey patches React to notify you about potentially avoidable re-renders. (Works with React Native as well.)
https://www.npmjs.com/package/@welldone-software/why-did-you-render
MIT License
11.11k stars 196 forks source link

Problem: React has detected a change in the order of Hooks called by BrowserRouter #256

Closed KirianCaumes closed 1 year ago

KirianCaumes commented 1 year ago

Hello,

I have a problem with why-did-you-render and react-router-dom.

Problem

When I use the router and especially a link to change the page, this error is thrown:

Warning: React has detected a change in the order of Hooks called by BrowserRouter. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useRef                     useRef
2. useState                   useState
3. useLayoutEffect            useRef
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The problem seems to be inside the BrowserRouter and only appears when the why-did-you-render plugin is enable.

I've tried to add/remove React.StrictMode but it doesn't change anything.

Steps to reproduce

This issue can be reproduced with the starting template from Vite and the Typescript version.

// main.ts
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { BrowserRouter } from "react-router-dom";

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

(await import('@welldone-software/why-did-you-render')).default(React)

// App.ts
import { Link, useRoutes } from 'react-router-dom'

export default function App() {
  const routes = useRoutes([
    { path: "/", element: <>1</> },
    { path: "/2", element: <>2</> },
    { path: "/3", element: <>3</> },
  ])

  return (
    <>
      <Link to="/">1</Link><br />
      <Link to="/2">2</Link><br />
      <Link to="/3">3</Link><br />
      <br />
      {routes}
    </>
  )
}

Version of libraries:

I'm not sure what to try to fix or work around this problem, so thanks in advance for your help 🙏

bduff9 commented 1 year ago

I have the same issue with a brand new Remix project. This can be seen by running npx create-remix@latest and then installing this package. All client-side routing breaks with the rules of hooks error, though in Remix it's on RemixBrowser.

Here is a sample repo showing the error, just clone, install deps, and run it to see: https://github.com/bduff9/remix-broken-whydidyourender

Waltari10 commented 1 year ago

Experiencing similar problem but in react native. Sorry, I don't have steps to reproduce, but this is the stacktrace.

Definedly not breaking rules of hooks in my code.

Simulator Screen Shot - iPhone 14 - 2022-12-01 at 13 27 28

vzaidman commented 1 year ago

The library will not work if any elements were created before it's loaded. so this:

(await import('@welldone-software/why-did-you-render')).default(React)

is certainly wrong.

Find a way to import it not asynchronously.

KirianCaumes commented 1 year ago

Solve the problem with this: https://github.com/welldone-software/why-did-you-render/issues/243#issuecomment-1132892461