Render is called twice when fetching data from a REST API - reactjs

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

Related

React setState is not getting updated

I have added the below piece of code in my react project to set the state with the response of a method. But the state never updated. It is always null. May i know how to set the state here
_onload():any{
this._DataAccessObj = new DataAccess();
let result = this._DataAccessObj.getRequest(this.props.itemId).then((item:IRequest) =>{
console.log("item");
console.log(item);
this.setState ({
Request: item
});
console.log(this.state.Request);
console.log("setstate");
});
return;
}
From the documentation of ReactJS and lifecycle:
Every second the browser calls the tick() method. Inside it, the Clock
component schedules a UI update by calling setState() with an object
containing the current time. Thanks to the setState() call, React
knows the state has changed, and calls the render() method again to
learn what should be on the screen. This time, this.state.date in the
render() method will be different, and so the render output will
include the updated time. React updates the DOM accordingly.
The last part is important: The actual state object will be update later on the line, not directly when the setState method has been called.
On the same page:
React may batch multiple setState() calls into a single update for
performance.
Because this.props and this.state may be updated asynchronously, you
should not rely on their values for calculating the next state.

this.setState() not working properly - react.js

componentWillMount() {
let dID=this.props.match.params.datumID;
this.setState({datumID: dID});
console.log(dID);
console.log(this.state.datumID);
}
I'm just trying use setState() method.
But the problem is it is not working.
Here is what I get as output:
First console.log() : 66
Second console.log(): null
this.setState accepts a second argument as callback which is fired after the state is successfully changed.
componentWillMount() {
let dID=this.props.match.params.datumID;
console.log(dID);
this.setState({datumID: dID},()=>console.log(this.state.datumID));
}
side note : Move your code to componentDidMount.
componentWillMount() is invoked immediately before mounting occurs. It
is called before render(), therefore setting state in this method
will not trigger a re-render. Avoid introducing any side-effects or
subscriptions in this method.
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.
If you need to set the state based on the previous state,
read about the updater argument below.
this.setState((prevState, props) => {
return {datumID: props.match.params.datumID};
});
Because SetState() is an asynchronous function, use below code
componentWillMount() {
let dID=this.props.match.params.datumID;
this.setState({datumID: dID},
function(){
console.log(this.state.datumID)});
console.log(dID);
}
and if possible try to avoid compenentWillMount since it would be deprecated soon
setState() being an asynchronous function it is in progress of updating the state and javascript being single-threaded language it will execute the next line of code. So if you want to see the state value set you have to do something like this.
componentDidMount=()=> {
let dID=this.props.match.params.datumID;
this.setState({
datumID: dID
},()=>{
console.log(dID);
console.log(this.state.datumID);
});
}
Also I would recommend you to use componentDidMount as willMount won't work in the future as it is deprecated
this.setState is an asynchronous function that takes time and passes the newly assigned
state value over all of the React's life-cycle functions in order to update a state and trigger the re rendering of a component. Your first console logs out the value that is assigned to set state and the next console logs out the value that is currently residing in the state this.state.datumID. if you need to perform operations after setting state you can pass a callback that is triggered after a state is successfully updated.
this.setState({datumID: dID}, () => console.log(this.state.datumID) ); // this will log the updated value
Another thing I want to point out is componentWillMount will wont work in the future release. If you want to do something after DOM is rendered, use componentDidMount or you can perform pre-render task in the constructor of your Class Component.

React lifecycle methods

I have been doing react for a while and am familiar with some lifecycle methods but not so familiar with others
e.g. didMount is clearly for ajax requests or calling data from an api then loading it into the app
I think I have conquered shouldComponentUpdate, and have realised it is purely there for performance
but static getDerivedStateFromProps I cant really get my head around. is that for performance or does that add something else to the app?
and also componentDidUpdate, is this for performance again or where is a good example where I can use these?
clearly some methods are necessary to perform actions and actual requests. clearly some are there to improve performance etc. just would like to get some context around didUpdate and getDerived
thanks
Yo can understand the lifecycle hooks in react through this blog : https://medium.com/#baphemot/understanding-reactjs-component-life-cycle-823a640b3e8d
Lifecycle methods made to allow you to run code at particular times in the process.
componentDidMount() is invoked immediately after a component is inserted into the tree, we commonly use it to make API requests.
Using React Hooks
useEffect(() => {
makeApiRequest()
}, [])
componentDidUpdate() is invoked immediately after updating occurs (in the state or props). This method is not called for the initial render. 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
Using React Hooks
useEffect(() => {
doYourStuff()
})
The difference between componentDidUpdate and the Hook above that the Hook will be called in the initial render also. There is no 100% alternative to the componentDidUpdate() method.
componentWillUnmount() is invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, or cleaning up any subscriptions.
Using React Hooks
useEffect(() => {
return () => {
cleanUp()
}
})
getDerivedStateFromProps() is invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, or null to update nothing.
Read More -> React Lifecycle React Hooks

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?

why we prefer to write header or api request or ajax code in componentDidMount not in componentWillMount

why we prefer to write header or api request or ajax code in componentDidMount not in componentWillMount.
need simple and clear difference with example
You should use componentDidMount() because you need the component to be rendered in order to populate it with the data that you're fetching from the API.
componentWillMount(){
//Fetch API and set the State
}
render(){
return(<div>{this.state.myData}</div>)
}
When componentWillMount() fires up the <div> hasn't been rendered yet (does not exist at the moment in the DOM).
When using componentDidMount() in the other hand. The render method runs first creating the <div> element in the DOM, after that then componentDidMount() runs, fetching the data, you set your state and that creates a re-render of the component. That's why we use componentDidMount() to fetch data from the API. you can find more information here.
caveat: You should validate the state so you don't get undefined the first time the component is render (without the data from the API).
edgaromar90 the same case with constructor also. we usually set temporary state in constructor and constructor invokes before the initial render. both constuctor and willMount invokes before initial render, then why we are not using in componentWillMount

Resources