Is componentDidMount triggered everytime I set state somewhere in the class? - reactjs

I would like to know if componentDidMount gets triggered every time I setState(anywhere in the class)?
Second, I am calling a function fetchData inside componentDidMount, and fetchData is a database listener so it listens for changes in Firestore database. How is that called every time if I call it from componentDidMount?

The componentDidMount is called when the component is first added to the DOM (or render tree when on native), not when that component is subsequently updated/rerendered.
From the React docs on state and lifecycle:
The componentDidMount() method runs after the component output has been rendered to the DOM. This is a good place to set up a timer...
And the documentation on Component.componentDidMount:
componentDidMount() is invoked immediately after a component is mounted (inserted into the tree). Initialization that requires DOM nodes should go here. If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
Setting state merely causes the component to be rerendered.

Related

Why are browser api event subscribed to in componentDidMount in React?

In this talk https://reactjs.org/docs/hooks-intro.html the speaker write codes that resemble this :
class SomeComponent extends React.Component {
constructor(props){
super(props)
this.handleResize.bind(this)
}
handleResize(){
//do something with window.innerWidth
}
componentDidMount(){
window.addEventListener('resize',this.handleResize)
}
}
Why is the window.addEventListener part in componentDidMount ? Does it have to be ?
From the tone of the talk, I felt that this situation was pretty common.
I'm fairly new to react, and I would have put the browser api event subscription in the constructor just as well.
Is there any advantage that would have elude be as to why put this window.addEventListener in componentDidMount ? Or is it juste for readability purposes ?
To me it's quite simple.
First, you only want api call or event listeners to be called/initialised only once, componentDidMount() and constructor is guaranteed to run only once per mounted component.
However, I won't put api in constructor because if you want a UI update after your data is returned from the api, you need a state change, while you cannot set state in constructor. The only place that only run once and allow you to setState is componentDidMount().
For Event listeners I think it can be put in constructor/componentDidMount. However, the official docs do recommend that to be put in componentDidMount(). Have a look at this.
componentDidMount is called after the component is mounted and has a DOM representation. This is often a place where you would attach generic DOM events.
In general, constructors must not have any side effects.
And also React documentation already mentioned this:
Avoid introducing any side-effects or subscriptions in the constructor. For those use cases, use componentDidMount() instead.
The window.addEventListener define in the componentDidMount life cycle, because code defined inside componentDidMount is executed after the DOM have been rendered. And that would be the right moment to try to attach any event handler to element which is part of the DOM.
But if you did so inside constructor, there are many chance for that to be called before the DOM had been rendered completely.
Read more here
There are multiple reasons about componentDidMount()
In practice, componentDidMount is the best place to put calls to fetch data, for multiple reasons.
1- If you want to subscribe and unsubscribe your function then you need to call that function in componentDidMount() and to unsubscribe(after all operation) call in componentWillUnmount()
2-Using didMount makes it clear that data won’t be loaded until after the initial render. This reminds you to set up initial state properly, so you don’t end up with undefined state that causes errors.
3-componentDidMount() lifecycle method is called after render() to make sure successful DOM loading.
window.addEventListener('resize',this.handleResize)=>
You can call in constructor as well but later if you need to
unsubscribe, can't do because it's initial phase(called initially
only).

ComponentWillReceiveProps method does not invoke automatically unless there is some API which triggers this through mapStateToProps function

Suppose I have a React class based component named as "ComponentA". Now I have called the action creator (getCategories) inside componentDidMount hook of this component and get its response inside componentWillReceiveProps through mapStateToProps setting up and carrying state inside redux. Now if I switch to "componentB" and trying to get this already setted up state inside componentWillReceiveProps through mapStateToProps of "ComponentB", the componentWillReceiveProps never invoked unless there is an API call which forcing this to invoke. I want to invoke this method of "ComponentB" everytime I switch to this component without API call. Please let me know the correct solution of this problem. Thanks
As per you description, It is hard to resolve your issue, but this is my try.
As you are switching the component, assuming you click some link, you will never get data in componentWillReceiveProps because whenever you are switching the component, that component only go through below process as a newly mounted component.
componentWillMount() -> Render -> componentDidMount().
This is the process for newly mounted component.
The data you want in componentWillReceiveProps will only come when you pass data from parent to child and not when you switch the component.
As you are using redux, and changing some state in one component (ComponentA), you can access the changed state the another component's (ComponentB) ComponentDidMount().

Render is called twice when fetching data from a REST API

I am trying to interact with a REST API using React, and I have realized that when I fetch the data, render is called once without the data, and then again with the data.
This throws an exception when I try to process this data, but I can use an if statement to check if data is null or not. However, I am not sure if that's needed.
class App extends Component {
state = {
TodoList: {},
};
componentWillMount() {
axios.get("http://localhost:5001/1").then((response) => {
this.setState({
TodoList: response.data,
});
});
}
render() {
console.log(this.state);
return <h1>hello </h1>;
}
}
This is what I see in in the console:
That's perfectly normal.
Your App component flow as below:
Execute render method to load the component
execute codes in componentDidMount
Calling axios.get which is async operation
Receive data from step 2, update component state by using this.setState
App component detected there's an update on state, hence execute render method to load component again
Hence, you should definitely handle the case where this.state.TodoList has no data, which happened at first load
UPDATES:
component lifecycle componentWillMount is now deprecated which means you shouldn't be using it anymore. Replace it with componentDidMount instead. Functionally wise they should be no difference in your example
Initially, render method is called after cwm method. So console log shows the state's empty value first time.
But you have run an async operation in cwm method, so after it is done, the setstate method is called which causes the render method to run again.
Note: ComponentWillMount, componentWillUpdate and componentWillUpdate props method are deprecated.
You should move this API call to componentDidmount or ComponentDidUpdate method.
However, event after this, your console log will appear twice- one for initial render and second for setstate called after API call.
Note : componentWillMount is deprecated and will work until version 17.
Source - https://reactjs.org/docs/react-component.html#unsafe_componentwillmount
Most suitable React Lifecycle for calling APIs:
componentDidMount is the most prefered method to perform asynchronous tasks like API calls, setTimeouts , etc..
It'll work as -
On componentDidMount your API gets called
As per lifecycle order, lastly render method will be called. (Still API hasn't returned response). Your UI is displayed at initial paint.
Once API gets response, you use this.setState() which will force a re-render operation.
Again your UI changes are updated
Remember : this.setState() will only be called once whether you have called it once or more than once in lifecycle method

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.

ComponentWillMount and ComponentDidMount not synced

I am making a react application. I need to make an ajax call to fetch the data from server and populate this data in the rows of my component's table. I do my ajax call in componentWillMount and store the response in the state. Now my render fetched this state and populates it. I have a few questions though:
Am I doing it right to place ajax in componentWillMount?
My componentDidMount doesn't get the value of state which get's set in componentWillMount. This means the async is not complete while componentDidMount is trying to access it. How to solve this? setting async:false is really a bad option.
What all thing can be used in componentWillMount?
Yes, componentWillMount is called once before the render. This is the place to fetch data.
Probably when the component finished rendering, the componentDidMount called although the async operation didn't finished yet, therefore you get empty result.
You can use componentWillUpdate
componentWillUpdate() is invoked immediately before rendering when new
props or state are being received. Use this as an opportunity to
perform preparation before an update occurs. This method is not called
for the initial render.
Or shouldComponentUpdate,
shouldComponentUpdate() is invoked before rendering when new props
or state are being received. Defaults to true. This method is not
called for the initial render or when forceUpdate() is used.
It's a broad question, basically fetching data from actions, calling api's etc.
More info in docs
Am I doing it right to place ajax in componentWillMount?
The recommend approach is to place your initial network requests that modify state inside of componentDidMount, because in theory your ajax request could come back prior to React completing the mounting process which might lead to your state getting overwritten.
However, in practise people use both as the above scenario should never happen.
My componentDidMount doesn't get the value of state which get's set in
componentWillMount. This means the async is not complete while
componentDidMount is trying to access it.
That is the correct behaviour.
How to solve this? setting
async:false is really a bad option.
If you stop it then it's no longer async.
The best practise here would be to show a loading indicator:
add a loading property to state
set it to true just above your fetch request
inside .then and .catch set loading to false
inside render check if your data has arrived - if not display the loading indicator
If you don't want to show anything until your request comes back
You can return null inside of render which will prevent your component from being added to the DOM. You can then combine this with a flag state property to make sure the component gets mounted once your request comes back, i.e. something like this:
render() {
if (!this.state.initialRequestHasCompleted) return (null);
return (
<div>
...
</div>
);
}
What all thing can be used in componentWillMount?
What is the purpose of having functions like componentWillMount in React.js?

Resources