When exactly is `componentDidMount` fired? - reactjs

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.

Related

What does it mean by useState are asycnhronous in react

I found some old post that a guy having problem with his code in React and alot answer said that it was caused by because useState is asycnhronous. I was curious what it mean by asycnhronous and I found this article
useState is an asynchronous hook and it doesn't change the state
immediately, it has to wait for the component to re-render. useRef is
a synchronous hook that updates the state immediately and persists its
value through the component's lifecycle, but it doesn't trigger a
re-render
But i still don't understand what it means and why is such a problem. Can someone give me an example?
I would say this is one of the myth to call useState asynchronous.
IMHO, if you open the source code of react, I'm speaking to react 16.x and below (because i didn't read after 16), useState isn't asynchronous.
So why are we saying useState behaves as asynchronous code? We need some coding example.
const App = () => {
const [value, setValue] = useState(1)
const onClick = () => {
setValue(2)
console.log(value)
}
return <input value={value} />
}
In the above typical setup of useState, when you call setValue(2), value wouldn't become 2 right away. This is apparent if you put a console.log after that. Then why the input does show 2 instead of 1, you might ask?
That's because React made a second render to App, you can think of App has been called one more time after setValue. For this reason, people call useState async.
But then why I'm not calling useState async? well, this is a bit long story. The short story is that useState is implemented inside React using plain non-async codes, therefore you can't say a code async just because it has been called twice or it has been deferred to call. Async means a bit differently in Javascript. This is another topic which I won't get into here.
I don't want to speak for the React team as to why state changes are asynchronous, but here's some random dude's explanation. I'll be referring to the JavaScript event loop, which is basically a program that runs many times per second. Each time it runs, it processes a series of tasks synchronously. Asynchronous code is executed across several event loops. This is a very basic and oversimplified explanation - you should go read more about the event loop.
So your initial state declaration happens in your initial render - the first time the function is called. This initial render happens synchronously - meaning the function is executed top to bottom in a single event loop. It's worth pointing out that React components cannot be async:
const SomeComponent = () => {
const [foo, setFoo] = useState("bar");
return <div>The value of foo is "{bar}"</div>;
}
After your initial render, the state only changes when something happens: user clicks a button, the screen resizes, a timer interval fires, etc. Whenever an "event" happens, there can be a lot of processing going on in the JavaScript event loop.
Let's look at a button click, the event propagates all the way down and back up the entire DOM tree which contains the button. The browser is also rendering different states of the button, causing the browser to repaint. You also have developer code which is running in the button click handler which might be doing some heavy lifting like iterating over an array. This all happens within a single event loop. The point of this explanation is to convey that "a lot is going on". Eventually, the state will get updated with setFoo(...).
At this point, React now has to figure out which component changed, calculate and rerender your application in a virtual DOM, perform a diff with the actual DOM, and then apply any changes to the actual DOM. Only at this point does the browser finally paint the result to the screen. This whole operation can be very taxing on a CPU.
If react were to handle state changes synchronously, all of this virtual DOM diffing and calculating would happen in the same event loop as the initial button click. It is very likely that most apps would cause the browser to sporadically freeze and jitter because the CPU is doing so much work at one time.
There are also some other things to consider. Suppose the window resizes and a bunch of different components perform some calculations and update their state. You don't want react to synchronously rerender every time a component changes its state. You want react to kind of wait and collect a whole bunch of state changes and process them at the same time. Browsers also provide mechanisms like requestAnimationFrame to help web-based applications asynchronously render in such a way that works best for the user and their system/browser resources.
There are many other things to consider, but this post is getting long. Hope this helps.

Will componentWillMount run again if component is re-rendered because of parent component?

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.

React - how to use the lifecycle methods

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!

React lifecycle method when component is fully rendered

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.

How to animate a React component on render?

I am trying to animate a React component that contains data fetched from elsewhere. Placing it in a ReactCSSTransitionGroup worked fine. That is, until I altered the component's render() method to return false until the data has been fetched (to prevent it from being rendered without data).
Now, I guess the component is mounted immediately, at which point the animation classes are added, but only rendered afterwards. Is this thinking correct? How can I get the component to be animated when render returns the actual component?
ReactCSSTransitionGroup activates whenever components are added and deleted to its props.children. Since your component is mounted before you fetch data, nothing will happen after data is fetched (I think this is true even if the component's render() method returns false. Let me know in the comments if that is incorrect)
Here's a solution
Just don't mount the component (in the solution, it's a <div key="1"> tag) until the react class receives the data. Use component states on the parent component to keep track of the state of your asynchronous request.
The ReactCSSTransitionGroup doesn't play nicely with tables as it's default behaviour is to wrap tags with a span element. You can provide it with your own component, but I found the solution quite heavy and complex.
I have a different approach that allows a React component to animate each time its content changes. The animation is continually triggered by toggling between 2 duplicate CSS styles.
Other than the ReactCSSTransitionGroup, another way is to write your own css transitions with an 'enter' class that is added to the component in componentdidmount. Keep in mind that you should change the state in a requestAnimationFrame because otherwise your class would be added in the same event loop as it is mounted, thus wont animate. Here's an example:
https://codesandbox.io/s/zkm5015y1x
Also, more on event loop, a talk by Jake Archibald:
https://www.youtube.com/watch?v=cCOL7MC4Pl0

Resources