Material-ui: Hidden component: React has detected a change in the order of Hooks called by WithWidth(HiddenJs)

Created on 6 Feb 2020  ·  22Comments  ·  Source: mui-org/material-ui

React has detected a change in the order of Hooks called by WithWidth(HiddenJs). This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://fb.me/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. useState                   useState
3. useLayoutEffect            useLayoutEffect
4. useContext                 useContext
5. useState                   useState
6. useEffect                  useEffect
7. useContext                 useContext
8. useState                   useState
9. useEffect                  useEffect
10. useContext                useContext
11. useState                  useState
12. useEffect                 useEffect
13. useContext                useContext
14. useState                  useState
15. useEffect                 useEffect
16. useContext                useContext
17. useState                  useState
18. useEffect                 useEffect
19. undefined                 useContext
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
in WithWidth(HiddenJs) (created by Hidden)
in Hidden (created by Tags)
in Tags (created by Candidates)
in tr (created by ForwardRef(TableRow))
in ForwardRef(TableRow) (created by WithStyles(ForwardRef(TableRow)))
in WithStyles(ForwardRef(TableRow)) (created by TableBase)
in tbody (created by ForwardRef(TableBody))
in ForwardRef(TableBody) (created by WithStyles(ForwardRef(TableBody)))
in WithStyles(ForwardRef(TableBody)) (created by TableBase)
in table (created by ForwardRef(Table))
in ForwardRef(Table) (created by WithStyles(ForwardRef(Table)))
in WithStyles(ForwardRef(Table)) (created by TableBase)
in div (created by TableBase)
in div (created by TableBase)
in div (created by TableBase)
in TableBase (created by ConnectFunction)
in ConnectFunction (created by Context.Consumer)
in withRouter(Connect(TableBase)) (created by WithTheme(withRouter(Connect(TableBase))))
in WithTheme(withRouter(Connect(TableBase))) (created by WithWidth(WithTheme(withRouter(Connect(TableBase)))))
in WithWidth(WithTheme(withRouter(Connect(TableBase)))) (created by WithStyles(WithWidth(WithTheme(withRouter(Connect(TableBase))))))
in WithStyles(WithWidth(WithTheme(withRouter(Connect(TableBase))))) (created by _class)
in _class (created by Context.Consumer)
in injectIntl(_class) (created by Candidates)
in Candidates (created by ConnectFunction)
in ConnectFunction (created by Context.Consumer)
in withRouter(Connect(Candidates)) (created by WithStyles(withRouter(Connect(Candidates))))
in WithStyles(withRouter(Connect(Candidates))) (created by WithTheme(WithStyles(withRouter(Connect(Candidates)))))
in WithTheme(WithStyles(withRouter(Connect(Candidates)))) (created by _class)
in _class (created by Context.Consumer)
in injectIntl(_class) (created by Context.Consumer)
in Route (created by RootRouter)
in Switch (created by RootRouter)
in RootRouter (created by Root)
in div (created by Root)
in div (created by Root)
in div (created by Root)
in Root (created by WithTheme(Root))
in WithTheme(Root) (created by WithStyles(WithTheme(Root)))
in WithStyles(WithTheme(Root)) (created by ConnectFunction)
in ConnectFunction (created by Context.Consumer)
in Route (created by PrivateRoute)
in PrivateRoute (created by ConnectFunction)
in ConnectFunction (created by AppRouter)
in Switch (created by AppRouter)
in div (created by AppRouter)
in Router (created by AppRouter)
in AppRouter (created by ConnectFunction)
in ConnectFunction (created by WithStyles(undefined))
in WithStyles(undefined) (created by Context.Consumer)
in injectIntl(WithStyles(undefined)) (created by IntlApp)
in IntlApp (created by ConnectFunction)
in ConnectFunction (created by Context.Consumer)
in injectIntl(Connect(IntlApp)) (created by ThemableApp)
in ThemeProvider (created by ThemableApp)
in IntlProvider (created by IntlProvider)
in IntlProvider (created by ConnectFunction)
in ConnectFunction (created by ThemableApp)
in ThemableApp (created by ConnectFunction)
in ConnectFunction (created by WithTheme(undefined))
in WithTheme(undefined) (created by App)
in Provider (created by App)
in MuiPickersUtilsProvider (created by App)
in ErrorBoundary (created by App)
in App
external dependency

Most helpful comment

Снимок экрана 2020-02-10 в 18 58 46

We encountered the same error Rendered more hooks than during the previous render.

All 22 comments

Please provide a full reproduction test case. This would help a lot 👷 .
A live example would be perfect. This codesandbox.io template _may_ be a good starting point. Thank you!

I examined the source code and in the WithWidth function a hook called within a loop. I think in a way that will cause my problem (I can't reproduce it, it sometimes appear).
Why do you suppress he hook warning (at line 56 of withWidth.js)?
See: https://reactjs.org/docs/hooks-rules.html

This happens for example as the theme is changed.

We are seeing something similar in our web application, but instead of a different order, React complains that more hooks were rendered than during the previous render.

This issue has started to happen on a somewhat small scale two days ago. I haven't been able to find any changes in the MUI source code that could cause this, and we are not able to reproduce it on our machines. It does come from MUI's withWidth, according to the stack traces we've seen so far.

It mostly seems to trigger when a user navigates away. On some navigations, we change the theme, but not on all. This issue has also occurred when a user started a navigation that did not change the theme, so my guess is that it occurs whenever there's a lot of rendering going on.

Right now, my guess is that this is a browser issue. All of the events we've seen of this so far have occurred in Chrome (which might be a bias due to our user base). However, this bug's appearance coincides very nicely with the release of Chrome 80, so I feel that there's a regression in there causing this.

Really not sure how to go about this.

The way we implement withWidth is with the assumption that the number of breakpoints doesn't change. If they change then the number of hook calls.

IMO this HOC should not use hooks at all and be reverted to the previous version following the principle of least surprise.

That would probably work. The weird thing about this issue though is that we're not changing the number of breakpoints in our theme; we only update some colors. While I agree with your opinion that this code should not be using hooks, it also should not be throwing errors here as the number of breakpoints remains unchanged (in our case at least).

Edit: I would say that hooks themselves should be fine for withWidth, but the way they're currently used is dubious.

@eps1lon Regarding the breakpoint issue, reverting is one option, I think that we could also consider

  1. warning against dynamic change of breakpoints (least surprise & explicit no support)
  2. removing the Hidden component (CSS version to be replaced with the system, JS version to be replaced with a component version of useMediaQuery).

I think using using media queries for this is misguided. Did we try it with a simple resize listener?

@eps1lon I don't remember trying with a resize listener, we should probably consider the tradeoff.

I think that the main pros of using media queries for this is that idea to rely on a single "infrastructure". I mean, if we consider tests and server-side rendering. These two need to be configured to play, more or less, nicely with the idea to JS conditionally render based on the size of the screen.

From what I remember, the initial hook version hadn't a limitation with dynamic breakpoints. It was dropped in https://github.com/mui-org/material-ui/pull/16343/files#diff-33a03947dab1f076cc15415d619e4987L55, in exchange for a simpler useMediaQuery logic. I think that we did the right move, and that we could explicitly not support dynamic breakpoint values in the theme. "You set it once, and you stick to it", this sounds to me like an approach we could recommend.

Maybe this issue is another of (same type) #16580? 🤔 But without a reproduction, it's impossible to tell.

I think that the main pros of using media queries for this is that idea to rely on a single "infrastructure". I mean, if we consider tests and server-side rendering.

Excellent point. It seems like there isn't a perfect solution for this. For now I'd say we add a helpful warning if we know that the number of calls changes.

I wouldn't be surprised if hot-reloading or react-fresh have issues with the loop call though.

Снимок экрана 2020-02-10 в 18 58 46

We encountered the same error Rendered more hooks than during the previous render.

Any workaround for this? It's happening a lot in my production app now

It's hard to reproduce, but I'm pretty sure hooks aren't supposed to be used like that in a non-react function.

https://medium.com/@jonchurch/how-to-fix-react-error-rendered-fewer-hooks-than-expected-e6a378985d3c

Any workaround for this? It's happening a lot in my production app now

No, we could not reproduce this case. But this error appears from time to time.
We will try to reproduce this error by modifying the file withWidth.js.

I will write here if we find out the reason

Because our system is going in production as well, I had to rewrite the useWidth function. Also I had update the Hidden component and the withMobileDialog because they have a dependency on this function.
I did this a few days ago and since then I don't have the error anymore.

It's happening because hooks (useState and useEffect) are being called from a function that's not rendered as a react component.

_6798_Error__Minified_React_error__310__visit_https___reactjs_org_docs_error-decoder_html_invariant_310_for_the_full_message_or_use_the_non-minified_dev_environment_for_full_errors_and_additional_helpful_warnings__-_stark-peak-26561_-_Rollb

https://reactjs.org/docs/error-decoder.html/?invariant=310
"Rendered more hooks than during the previous render."

https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/useMediaQuery/useMediaQuery.js#L44

@hashwin Whether a function is rendered as a React component or not does not matter too much; you can write your own hook that uses useState (or other hooks) and it'll work just fine, even though it isn't rendered directly by React. Although the usage of a hook in reduce is debatable, it really should work fine if you don't change the number of breakpoints.


Over the past few days, we've seen this error pop up more and more in our error logging tools. All cases have occurred in Chrome 80, and our first case coincides with its release. The release notes state that some 'higher-order functions were optimized' and I still have suspicions that this may have something to do with this issue.

Oh wow, a broken .reduce method in Chrome 80 would explain the errors 😮.

Since this was fixed in chrome (though unreleased) I'm closing.

We do have leverage detecting an order change if the breakpoints length changed but this was not the cause here.

This worked for me:
Source: StackOverflow
makeStylesreturns a hook which you are passing to withStyles. This is what throws you that error. You should just pass on the styles to withStylesinstead without the use of makeStyles

const styles = (theme) => createStyles({...});

...


export default withStyles(styles)(CreateCategory); 
Was this page helpful?
0 / 5 - 0 ratings

Related issues

rbozan picture rbozan  ·  3Comments

FranBran picture FranBran  ·  3Comments

newoga picture newoga  ·  3Comments

activatedgeek picture activatedgeek  ·  3Comments

pola88 picture pola88  ·  3Comments