I need to do some size calculations when a component is fully rendered. The componentDidMount method, however fires as soon as the component is rendered, but it's children are not. This code for example:
componentDidMount(){
console.log(findDOMNode(this).childNodes.length);
}
outputs 0
What is the proper way to trigger some code once a component has been fully rendered, together with any descendant components.
Edit: I don't want to use componentDidUpdate since that method fires on any update. I just need this to be run once.
Edit2: As #NaisheelVerdhan points out, the docs say that componentDidMount ins invoked on children first, but in this case I'm confused as to why my above example returns 0
Typically you want to perform calculations in the render method itself. Is there some reason you cannot do that?
I am sorry everyone.
The component I was rendering initially mounted empty and was filled later. #NaisheelVerdhan was entirely correct.
Related
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.
As far as I know these are the scenarios when react calls the render() method provided shouldComponentUpdate() is not implemented.
when your component get mounted initially
when state got changed using this.setState()
when your component receives new props
when this.forceUpdate() get called.
Is there any other scenarios that I am missing?
Yes there's one more case I can think of. When parent component is re-render.
Every time a component is re-render all its children get re-render too. Unless you implement shouldComponentUpdate method in the children.
Hope it helps.
when context gets changed render gets called
This is a recurring problem I have with React. The componentDidMount method is guaranteed to be fired when the component is rendered for the first time so it seems like a natural place to take DOM measurements like heights and offsets.
However, many times I receive wrong style readings at this point of the component's lifecycle. The component is in the DOM, when I break with the debugger, but it's not yet painted on the screen. I get this problem with elements that have width/height set to 100% mostly.
When I take measurements in componentDidUpdate - everything works fine, but this method will not fire at the initial render of the component.
So my question is - when exactly is componentDidMount fired because it's obviously not fired after all the browser paints are done.
EDIT:
This Stackoverflow issue deals with the same subject:
It also references this github conversation that explains what happens
Inside a react component tree, componentDidMount() is fired after all children components have also been mounted. This means, that any component's componentDidMount() is fired before its parent has been mounted.
So if you want to measure DOM position and sizes etc, using componentDidMount() of a child component is an unsafe place/ time to do this.
In your case: to get accurate reading from 100% width/height components, a safe place to take such measurements would be inside the componentDidMount() of the top react component.
100% is a width/height relative to the parent/ container. So measurements can only be taken after the parent has been mounted too.
As you may know, componentDidMount is triggered only once immediately after the initial rendering.
Since you are taking measurements, it would seem you would want to also trigger your measuring when componentDidUpdate in case your measurements change when your component updates.
Please note that componentDidUpdate does not occur for the initial render so you likely need both lifecycle events to trigger your measurement handling. See if this second event triggers for you and if it has different measurements.
In my opinion you should avoid using setTimeout or requestAnimationFrame when possible.
React Lifecycle Reference.
It is called only once when the component mounted. That’s the perfect time to do an asynchronous request to fetch data from an API. The fetched data would
get stored in the internal component state to display it in the render() lifecycle method.
Simple: It Run After Render Functions
If you want to respond to something being mounted in the DOM, the most reliable way to do that is with a ref callback. For example:
render() {
return (
<div
ref={(el) => {
if (el) {
// el is the <div> in the DOM. Do your calculations here!
}
}}
></div>
);
}
you can try delaying logic in componentDidMount() with requestAnimationFrame(). the logic should occur after the next paint.
however, we'd need to know more about your code to see why the nodes haven't been painted. i've never hit that problem. componentDidMount() fires right after the dom nodes are added to the page, but not necessarily after they have been painted.
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!