react: useEffect callback never called
I want to report a bug. My problem is that the callback function I pass to useEffect()
is never called in my app. I uploaded a minimal app here that reproduces the issue.
As you can see, I render a couple of nested components. After the initial render, I update the component state inside a useEffect()
callback. However, this callback is only executed for the first two components, not for the third level component. The result is that the third and subsequent levels are not rendered at all.
I suspect that this is a bug in React and not a misuse on my side because doing any of the following changes will let the component tree render correctly in all levels:
- Don’t use multiple React roots. If I remove the last (yellow)
ReactDOM.render()
call, then the second (red) component tree will render correctly. - Don’t conditionally render child components. Removing the
message !== DEFAULT_MESSAGE
check (main.tsx
, line 20) causes the component trees to render correctly. - Use
useLayoutEffect()
instead ofuseEffect()
.
If you need additional information to reproduce the issue or have any questions, let me know. I’d like provide any help I can!
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 8
- Comments: 16 (4 by maintainers)
Commits related to this issue
- test: fix for #17066 — committed to aleclarson/react by aleclarson 5 years ago
- Regression test: Effects dropped across roots See #17066 — committed to acdlite/react by acdlite 5 years ago
- fix: replace useEffect calls with useLayoutEffect An attempt to work around this issue: https://github.com/facebook/react/issues/17066 — committed to alloc/wana by aleclarson 5 years ago
- [Bugfix] Passive effects loop The bug ------- In a multi-root app, certain passive effects (`useEffect`) are never fired. See #17066. The underlying problem ---------------------- The implicit con... — committed to acdlite/react by acdlite 5 years ago
- [Bugfix] Passive effects triggered by synchronous renders in a multi-root app (#17347) * Regression test: Effects dropped across roots See #17066 * [Bugfix] Passive effects loop The bug ---... — committed to facebook/react by acdlite 5 years ago
Here is somewhat minimal reproduction:
Some observations:
render()
s, it worksuseLayoutEffect
, it worksOther
doesn’t calluseEffect
, it worksrender()
is delayed, it worksB
orC
are rendered unconditionally, it workssetEffect
is delayed, it workshttps://github.com/react-navigation/hooks#only-for-react-navigation-v3--v4-not-v5
Fix released in 16.12.0
@WxSwen: I have no solution for the bug, but I found a workaround that works for me. Depending on your requirements, it might or might not help you, but I thought I might just share it. 😃
It seems the problem occurs when I have multiple React instances on the page (multiple
ReactDOM.render()
calls). And shortly after I found this bug and opened the issue, I also ran into another challenge with multiple React instances: I wanted to share context between all components on the page, but for that to work, they must be in the same React render tree.So what I ended up with was to go back to a single React instance. Instead, I call
ReactDOM.render()
only once, render into a disconnected<div>
, and use React portals to render my individual components into their respective places on the page. For example:@kunukn Sorry, I forgot to add an effect condition. I changed the
useEffect()
call (see diff), but the result stays the same: Components level 3 and beyond don’t render.edit: Tested my change in your codesandbox, saw that I missed the
level
variable as an effect dependency, updated my repository again. Still the same error - as you can see from the missingconsole.log()
output, the effect callback doesn’t even get called once.