Possible cause and solution for this warning - reactjs

Warning : Cannot update a component (X) while rendering a different component (Y). To locate the bad setState() call inside Y, follow the stack trace as described in :

There are suggestions on this document. It looks like the same warning.
doc door
It is supported to call setState during render, but only for the same component. If you call setState during a render on a different component, you will now see a warning:
Warning: Cannot update a component from inside the function body of a different component.
This warning will help you find application bugs caused by unintentional state changes. In the rare case that you intentionally want to change the state of another component as a result of rendering, you can wrap the setState call into useEffect.

Related

UseEffect: why is fetching data considered a side-effect but not accessing window.location?

I always thought of a side-effect as a read or write operation that is performed while rendering a functional component, and that accesses resources outside of those provided as props. Sort of like the definition of a pure function.
So when I needed to read window.location, I figured it had to be in a useEffect. Turns out the linter doesn't require that window.location be a dependency, so I guess it's ok to access window directly. This means my mental model of a React side-effect is wrong... But why?
If merely fetching data (which is a read operation) is considered a side-effect, then why isn't window.location?
So now I'm wondering, are functional components actually not really pure? Are they only "write pure" but not "read pure"?
How the useEffect or any other memoizing hooks(useCallback, useMemo,...) work works is:
Component re-renders
The dependency list is looked through to detect changes in any of them
If a change is detected, the function inside the useEffect is called
The issue with window.location or any other outer scope variables is that they do not initiate a component re-render to begin with.
This is the exact message on ESLint
Outer scope values like 'window.location.href' aren't valid
dependencies because mutating them doesn't re-render the component
And to answer your question, yes and no.
According this article :
A React component is considered pure if it renders the same output for
the same state and props
So if you add a dependency to an outer scope variable like window in your component, you can't call that component pure anymore.

useEffect or useMemo for API functions?

which is the best hook for dispatching API calls in a component. Usually I use useMemo for calling the API on the first render, and useEffect if I need extra side effects, is this correct? Becouse sometimes I get the following error:
'''index.js:1 Warning: Cannot update a component (Inscriptions) while rendering a different component (PaySummary). To locate the bad setState() call inside PaySummary, follow the stack trace as described in ...''''
That happens when I route to a component and rapidly change to another one, it doesn't "affect" the general behaivour becouse if i go back to the previous component it renders as expected correctly. So how should I do it?
Calling an API is a side effect and you should be using useEffect, not useMemo
Per the React docs for useEffect:
Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects. Whether or not you’re used to calling these operations “side effects” (or just “effects”), you’ve likely performed them in your components before.
Per the React docs for useMemo:
Remember that the function passed to useMemo runs during rendering. Don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect, not useMemo.
Performing those side effects (and modifying state) during rendering or with useMemo is the reason you encounter the errors you mention.
basically I rather to use useEffect in componentDidMount manner, with no dependency like below
useEffect(() => {
// Api call , or redux async action here...
}, [])
for calling api's at component mount state.
most of the time i find my self using useMemo for memoising the data at functional Component render level, for preventing the variable re-creation and persist the created data between renders except the dependency changes.
but for the context of your question, there is a hook called useLayoutEffect which is primarily used for actions to happen before painting the DOM, but as i said basically most of the time in projects i find calling apis in a simple useEffect with no dependencies aka, the did mount of your component, in order to load the required data for component!
A bit late but, while everything mentioned above is completely true; the error
'''index.js:1 Warning: Cannot update a component (Inscriptions) while rendering a different component (PaySummary). To locate the bad setState() call inside PaySummary, follow the stack trace as described in ...''''
Has to do with the fact that the API call is Asynchronous and when you rapidly change the pages, the set state call (for updating the data returned from the API call I assume) is still waiting to be called after the data is returned from the API. So, you have to always clean up your Async functions in useEffect to avoid this error.

React state update while rendering

I need to update a state in my react app while rendering the content. Is there any option to update state while rendering.
Note: I am very new to react
You can use componentDidUpdate() Lifecycle method.
and inside componentDidUpdate() function update your state.
FYI: componentDidUpdate() calls every time if component gets updtated.
https://reactjs.org/docs/react-component.html
Futureproofing Note: answer relevant to v16.4.
The answer to your question depends on what you mean by saying "while rendering".
When react invokes the render method of a component, it does not really render anything, yet. The results of the render method will undergo "reconciliation", which means that it will be compared to what's rendered at the moment. If a difference is detected, react will actually re-render the DOM, as effectively as it can.
This means that you can not do anything when react is actually rendering / re-rendering the DOM, since your code is not being executed.
You can, however, do something after the render method has been invoked.
As others have stated before me, the componentDidUpdate method is the place.
Note that the fact that this method has been invoked does not necessarily mean react has re-rendered the DOM. It only assures that the component is in sync with the DOM.
Do note that since setting state CAN cause a re-render, so you should really be careful about setting state in componentDidUpdate - or you might cause an infinite loop of sorts.
Even if you correctly implement shouldComponentUpdate, stopping the render cycle from ever reaching cDU- react docs suggest the result of sCU can be taken as a hint in the future, which will break your app in future releases.
So, if you must setState in cDU - you must check that this setState is required, and is not a side-effect of setting the state in the first place.

Warning about calling setState on an unmounted component

The warning:
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the _class component.
Any idea where it can come from. Gotchas or things like that ?
I already looked at all the setState in my code and replaced them to make sure. Can't find where it comes from...
My observations so far:
Only happens in my tests
No problem in the browser
I thought I had more... but with more testing I got all confuse because it didn't fit the patterns I thought I understood...
So ! I understand what the error is but this time the warning is about a _class component so I'm lost... I just upgraded to react-router v4 and it needed a lot of changes so it's hard to localize the source of the warning.
Anyone had had a similar problem before ?
EDIT:
I found the setState that were causing problem. It was in react-router-server. I'll look into it to see if I can fix it !
Thanks #zerkms for the idea to look with a debugger to get the line number since there was no trace in the terminal.
I used the v8 experimental inspector(https://stackoverflow.com/a/39901169/3687661). Works pretty good :)
This is common due to async activities like API calls. For example, this happen when you try to set a state after you receive the data from the server and the corresponding page to receive that state is not mounted.
To avoid this, check if the component is mounted before setting state in that component. Use a flag to check, say this.mounted = true in componentDidMount and change the flag to false in componentWillUnmount. Use this.mounted across the component to check if the component is mounted. This will fix the warning.
Hope this helps!
This usually happens when you call this.setState within a setTimeout or setInterval or some other deferred function.
If you are using setTimeout/setInterval make sure you call clearTimeout/clearInterval in componentWillUnmount.

ReactJS: What is the difference between componentDidUpdate and the second parameter of setState?

Is there any difference between those 2 functions? (besides their arguments)
It seems like those methods have the same triggers, isn't it?
Appreciate your help :)
componentDidUpdate is called whenever the component has re-rendered, which might be caused by either:
a change in state
a call to forceUpdate
a parent component re-rendering (or another call to React.render in the case of the top-level component)
The setState callback will only be called once the state transition has completed and the component has re-rendered.
The difference is the usage of those two: componentDidUpdate() needs to be declared only once per component, while the callback argument of setState() needs to be passed in every place the setState() method is called.
It's like putting all your eggs in one basket: you don't need to carry around different bags, however if you might want to boil some of the eggs and some to make an omelette from, and in this case you use multiple bags.

Resources