question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

React 16.13 throws a warning when "nesting" useInjectReducer calls

See original GitHub issue

After upgrading to React 16.13, we started getting this warning in many places:

image

More info about it in the 16.13 announcement post.

Here’s how it happens in our case:

  • Have ParentContainer with useInjectReducer
  • Have ChildContainer with useInjectReducer
  • When ChildContainer’s useInjectReducer is called, the warning appears.

This happens because calling useInjectReducer calls store.replaceReducer synchronously during the render of the ChildContainer.

From what I understand, we’re not technically updating the state of a component during the render of another component but we are updating the ReactReduxContext - which contains the store and is also consumed by ParentContainer via useStore inside useInjectReducer - so that must be enough to trigger the warning.

The suggestion by the React team is to “wrap the setState call into useEffect”.

Up until September of last year, this is exactly how useInjectReducer worked: injection happened inside an effect. However, doing the injection inside an effect caused a different issue: we couldn’t guarantee that the reducer or saga was always injected before a relevant action is dispatched. (Discussed in RBP here.)

Does anyone have any thoughts or suggestions regarding how we could fix this?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:3
  • Comments:54 (3 by maintainers)

github_iconTop GitHub Comments

12reactions
BenLorantfycommented, Jul 26, 2020

Ok after much investigation I’ve found a few scenarios where this can happen:

  1. Selectors that return a new object or array are not memoized
    • These include selectors that use .map and .filter
  2. Redux devtools are installed.

So we have two options:

  1. Make no code changes and update the documentation to explain these reasons and how to fix them. 1 can be fixed by properly memoizing. 2 can be fixed by setting shouldHotReload to false in the dev tools options.
  2. Use useLayoutEffect instead of injecting reducers synchronously on the first render.
    • This will mean sagas and reducers will inject before any other useEffects However, it will run after children’s useLayoutEffect. So if anyone is using dispatch inside a useLayoutEffect, it might not get picked up

Opinion I think we should do a combination of the above:

  1. Mention in the docs that parts of the app may re-render unexpectedly when using useInjectReducer, and that pages should be able to handle that. For example, an order shouldn’t be placed twice because a component re-rendered. This is how you’re supposed to write react components anyway.
  2. Change our injection mechanism to use useLayoutEffect instead of injecting during the render. This is because in truth replacing reducers is a side-effect, and may cause renders in other parts of the app for any number of reasons. As one example, you don’t have to use memoized selectors, and forcing people to do so is probably not good.
  3. Make useInjectReducer return a boolean indicating if the reducer is injected. Consumers can use this value to determine whether to render children or not, which can help avoid race conditions when consumers are dispatching actions inside useLayoutEffect. This should be rare enough that it’s not used often.
  4. Mention the useLayoutEffect race condition in our docs
  5. Possibly introduce a new api called “createManager” that would avoid these race conditions by only rendering it’s children after the reducer/saga is injected
  6. The one thing I’m not sure about is whether we should recommend setting shouldHotReload to false. If set to false users will suffer https://github.com/reduxjs/redux-devtools/issues/378 but if set to true you might get different behaviour between dev and production. I’ll try to come up with an example of this.

More resources: https://blog.logrocket.com/post-hooks-guide-react-call-order https://codepen.io/benlorantfy/pen/bGEJveX

4reactions
mdaffancommented, Nov 12, 2020

Any update on this issue?

Read more comments on GitHub >

github_iconTop Results From Across the Web

React v16.13.0 – React Blog
Today we are releasing React 16.13.0. It contains bugfixes and new deprecation warnings to help prepare for a future major release.
Read more >
Cannot update a component from inside the function body of a ...
I got the following for a react native project while calling navigation between screens. Warning: Cannot update a component from inside the ...
Read more >
Hooks - React Redux
When the function component renders, the provided selector function will be called and its result will be returned from the useSelector() hook.
Read more >
React hooks: how to use useState and useReducer effectively?
There are only two rules to follow. 1. Only Call Hooks at the Top Level i.e. not within conditionals, loops, or nested functions....
Read more >
8 common React error messages and how to address them
Warning : Each child in a list should have a unique key prop; Prevent usage of Array index in keys; React Hook useXXX...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found