Is there ever a situation where componentDidUpdate would NOT fire, even if the props updated in React?
There are 3 conditions that can cause componentDidUpdate to not fire:
1) You wrote a custom shouldComponentUpdate that returned false.
2) The internal react methods determined that there was no change in the virtual DOM, so it chose not to re-render.
3) You extended something other than React.Component (such as PureComponent) which has a default shouldComponentUpdate method that returned false.
You can suppress a render with returning false in shouldComponentUpdate().
So yes, in that case componentDidUpdate() won't fire.
this can also happen, if your component is in a list and the key of your component changes (ie. on every render) or the key is missing, or the key is duplicate, etc.
refer to docs for details:
https://reactjs.org/docs/lists-and-keys.html
A common situation where this occurs is when multiple prop changes occur which don't effect anything in the virtual DOM.
For example you may wish to display a success message if an API returns 200 status code, with props that change like this:
API not called:
this.props.apiState == false
API called:
this.props.apiState == 'loading'
API successful:
this.props.apiState == 'success'
In this situation componentDidUpdate will only fire once, and if you console log this.props.apiState at the time it is fired you will see that it is loading. So any trigger in componentDidUpdate that is waiting on success will not occur.
ComponentWillReceiveProps deals with this issue in older versions of React, and in newer versions of React you can use shouldComponentUpdate to force an update when your desired prop change occurs.
Nathan response is correct but it did not solve my problem when I searched for the same answers.
Sometimes it looks like props are updated but it is whole new component rendered with different props. Check componentDidMount (add console.log in it for example) to see what exactly happens.
Related
An example of the issue is found on CodeSandBox. Am I short circuiting myself between TRUE/FALSE values?
Can someone please help explain why the state variable isOptionOne is not being set as expected? Upon calling setIsOptionOne I would think that I can use isOptionOne in the remaining lines of code of the function. Unfortunately, that does not seem to be the case. To verify, see the console.log output. The two values for isDefault and isOptionOne should match.
Where am I going wrong? Thank you.
That is the expected behavior. React batches the state updates, which means it doesn't immediately update the state and re-render everything after each setState method call. From official documentation:
setState() enqueues changes to the component state and tells React
that this component and its children need to be re-rendered with the
updated state. This is the primary method you use to update the user
interface in response to event handlers and server responses.
Think of setState() as a request rather than an immediate command to
update the component. For better perceived performance, React may
delay it, and then update several components in a single pass. React
does not guarantee that the state changes are applied immediately.
setState() does not always immediately update the component. It may
batch or defer the update until later. This makes reading this.state
right after calling setState() a potential pitfall. Instead, use
componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update
has been applied. If you need to set the state based on the previous
state, read about the updater argument below.
Additionally, the above document is for the traditional class component's setState API. If you want to detect a change in your hook-based state, use useEffect.
Will componentDidUpdate always fire for a component that renders empty fragment/null ? It receives redux connected props from the parent container.
This component needs to access previous props and compare, then make an API call based on it. It doesn't have UI, so it renders empty fragment (or null)
EDIT : It is working and firing componentDidUpdate in my sample application. Is this guaranteed to be the behavior always?
It says here that there is a chance it may not fire when there was no change in the virtual DOM: Props updated, componentDidUpdate did not fire
MyContainer
|
-MyComponent
Yes it run every time instead at time of first initial render
Yes componentDidUpdate is called every time, even when rendering null. You can check this in the react documentation: React Lifecycle
Will componentWillMount run again if component is re-rendered because of parent component?
No, componentWillMount is called only once.
Also, componentDidMount is called only once.
componentDidUpdate is called on every re-render.
To correctly understand about the react lifecycle methods you can go through this link.
https://engineering.musefind.com/react-lifecycle-methods-how-and-when-to-use-them-2111a1b692b1
The short answer is NO
It's called once right before your component is about to be rendered to the DOM.
The long answer is:
componentWillMount
Your component is going to appear on the screen very shortly. That chunky render function, with all its beautifully off-putting JSX, is about to be called.
Most Common Use Case: App configuration in your root component.
Can call setState: Yes, but don't. Use the default state instead.
componentDidMount
Here is where you load in your data. ComponentDidMount is also where you can do all the fun things you couldn’t do when there was no component to play with. Basically, here you want to do all the setup you couldn’t do without a DOM, and start getting all the data you need. Most Common Use Case: Starting AJAX calls to load in data for your component.
componentWillReceiveProps
Perhaps some data that was loaded in by a parent component’s componentDidMount finally arrived and is being passed down. Before our component does anything with the new props, componentWillReceiveProps is called, with the next props as the argument.
shouldComponentUpdate
shouldComponentUpdate should always return a boolean — an answer to the question, “should I re-render?” Yes, little component, you should. The default is that it always returns true. It's an awesome place to improve performance.
componentWillUpdate
Most Common Use Case: Used instead of componentWillReceiveProps on a component that also has shouldComponentUpdate (but no access to previous props). It’s basically the same as componentWillReceiveProps, except you are not allowed to call this.setState.
componentDidUpdate
Here we can do the same stuff we did in componentDidMount — reset our masonry layout, redraw our canvas, etc. Basically, we use it when it's all said and done, but we don’t want to waste time to redraw the canvas every time it updates. Most Common Use Case: Updating the DOM in response to prop or state changes.
componentWillUnmount
Here you can cancel any outgoing network requests, or remove all event listeners associated with the component. Basically, clean up anything to do that solely involves the component in question — when it’s gone, it should be completely gone.
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.
I keep encountering the same problem with React. I feel I should be using the lifecycle methods. (Other than just componentWillMount and componentWillReceiveProps). But they never seem to meet my purpose. Here are 2 examples:
Asynchronous loading
My parent component loads some data with AJAX. A grandchild component needs this data - which is passed down via props. Because of the timing the data may be available when the child component is mounted or not. I don't know whether to put the code in my grandchild component which depends on these props in componentWillMount() or in componentWillReceiveProps(). I end up having to put it in both. (Or in a method they both call).
Lifecycle methods are either called on the initial render or not. I want them to be called on both.
My component gets some data. (Using getStateFromFlux - a mixin provided by Fluxxor). This occurs several times during the cycle of loading the data with various flags set onto the retrieved data object: unloaded, loading and loaded let's say. This change of state causes a re-render.
I only want to render and show the data if there is something to show. So - my render method has the first line:
if data.loadState != 'loaded'
return '<span />'
Ok. Well. I thought - there must be a lifecycle method to fix this. So I've done this:
shouldComponentUpdate: function (nextProps, nextState) {
if nextState.loadState == 'loaded'
return true
else
return false //stops the render. Good.
}
At last I thought - I have used a lifecycle method.
But, alas, while this does stop the render being called in some cases - when there is no data - I still can't remove the hacky looking line about
if data.loadState != 'loaded'
return '<span />'
This is because shouldComponentUpdate is not called for the initial render. When this component first renders there is no data. loadState is 'unloaded'. The render method is still called. And I still need to avoid displaying the UI (with empty data fields).
In general terms - the lifecyle methods are either called only on the initial render or only on subsequent renders. For most of my uses cases this is singularly unhelpful. I want a method which is agnostic to whether it is the first render or a subsequent one.
What am I missing about React? (The only thing I can think of is is that it is designed to be used with an initial render server-side when you can be sure of your data - then once in the browser the lifecycle methods are about detecting changes).
Thanks
Don't know about loading but with unloading I would suggest;
if (this.props.data.loadstate == 'unloaded') return null;
Have that as the first line of the render. As you noted shouldComponentUpdate only applies to updates.
You're right that you should be using the lifecycle methods, they're awesome and let you hook into your components in a much more in depth way. But I don't think this is the case for your current situation
You could just conditionally render the grandchild only when the data is loaded by the parent and passed to the child. Then you'd only need the check in the child. It would look something like this:
// Child render method that has been passed data loaded by the parent
render: function() {
var grandChild = null;
if (this.props.data) {
grandchild = <GrandChild data={this.props.data} />
}
return (
<div>
{grandchild}
</div>
)
}
In this case, you only pass a data prop to the child component once the data has loaded. Thus, you're guaranteed that when the grandchild component does render, it will have the data that it needs. Although I'm not sure why you are so averse to displaying empty data fields, this should solve the problem.
You're correct, there is no React lifecycle method that fires regardless of whether it's the initial render or not. That being said, if you have to do both, you can always a combination of componentDidMount and either componentDidUpdate or componentWillReceiveProps. I'm not 100% sure why they did this, but a couple reasons that come to mind:
Ensures that React will not need to re-render a component before the initial render (ie. changing state in componentWillReceiveProps, triggering an update before the initial render). I'm not too familiar with the code-base, but I can easily see that causing problems.
Performance boost for the initial render to let your content load faster while the virtual DOM is initialized
I hope this helps solve your problem and sheds some light on the lifecycle methods!