React API call after component re-render - reactjs

I have a componentDidMount where I am calling an API and then have a this.setState({...this.state}).
Inside render, I have a button that calls delete function. Now when this delete is called I am re-rendering but I also want this API that is present in componentDidMount to be called because the delete functionality deletes some data in the same component, which should show updated value later.
The problem is, when I reload the page I get the data required but re-rendering does not show the required data.

Practically the API call code that you write in componentDidMount could be written as a separate function which you can then call, when you delete the data.
componentDidMount() {
this.fetchData();
}
// using arrow function to achieve correct context binding
fetchData = () => {
// your API call here
}
delete = () => {
// call fetchData here after delete
this.fetchData();
}

if your react version is going to be less than 16 , then you can us componentDidUpdate for that. This is been deprecated but still you can use UNSAFE_ flag before its name.
check this link from stackoverflow itself for a real world example: here
if you want to use a more robust way of handling that in react version 16 and above you could use getDerivedStateFromProps , for that you can check the corresponding way of handeling it from stackoverflow: here

Related

Api call in render method of reactjs

I have a code in which an API call is made inside the render method in a react app, is it correct?
The API call is made from a function placed inside a const function which is placed in another file
render method is place for presenting various elements to user and these elements can be used to trigger an api-call for various purposes. For example - checking validity of text entered in input-element, sending form-data async-ly to server, etc.
And this is a nice practice to put the code into various modules or separate files for better management, etc. for ex. call is wrapped inside a function and placed in a different file. Webpack helps in filling all various modules in place.
So it is alright to put api calls in render and calling a function defined inside another file for the same.
It is not correct.
1) If the api call is waiting for the call to complete(await or promise resolve), Then it is essentially blocking render.
2) React might call render function many times[it may or not lead to DOM update], which means you will be making redundant api calls as many times.
It is ok to do so, if it is in response to an event.
So No, just put the api call in componentDidMount or ComponentDidUpdate or if you are using hook, add a useEffect.
Good Luck!
It really depends on the use case.
There is nothing wrong with doing so as long as you aren't calling it everytime it re-renders. I assume you are making the request upon triggering of certain events(such as onClick). If yes, it may be cleaner to encapsulate it within a method.
async doSomething = () => {
// do the rest
// make API request
await getRequest();
}
return <>
<button onClick={() => this.doSomething()}/>
</>;
If the request is to be made only once and when the component is initialised, you should make that request within the componentDidMount lifecycle hook. According to the documentation for 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.
Otherwise, calling it on render() will result in the API request to be triggered everytime there is a re-render.

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

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

Deciding which redux container to make API calls from

In the example component tree, Component C and E both require the same data. This data is fetched from an API call which is triggered via dispatching an action.
My question is, where should this dispatching of the fetch action occur?
It could occur in the componentWillMount() (via mapDispatchToProps()) method of the first mutual parent component, Component B in this case. The problem with this is that component B now has an intimate knowledge of the data it's children require and I can no longer re-use Component C or E without some higher-order component.
Alternatively it could occur in componentWillMount() (again, via mapDispatchToProps()) of both Component C and E, potentially using a debounce on the action creation (helper libs available). My concern with this is that now Component C and E have some knowledge that they exist on the same page as each other otherwise they wouldn't debounce. Worse still, if Component C appears on another page without Component E then it is unnecessarily debouncing an action.
Does anybody know of a cleaner pattern for fetching data to be used by multiple child components?
One approach would be to have both components call the same thunk action creator, which should check to see if the request actually needs to be made. It might look something like this:
function loadSomeDataIfNeeded() {
return (dispatch, getState) => {
const state = getState();
if(!dataAlreadyLoaded(state) && !currentlyFetchingData(state)) {
dispatch(startFetchingData())
fetchData()
.then(response => {
dispatch(dataFetched(response));
});
}
}
}
So, track a "are we fetching right now?" value in your state, and also have logic to figure out if the data has already been loaded. That way, you can call the thunk multiple times and only actually have it fetch once.

Redux unsubscribe within componentWillUnmount still calls subscribe callback

I am manually hooking a React component up to a Redux store. Yes, I realize Dan Abramov of Redux recommends against this. I will be getting around to looking at react-redux eventually, but for now I want to understand what's going on.
componentDidMount() {
this.unsubscribe = store.subscribe(() => {
const storeState = store.getState();
this.setState({
someData: storeState.someData
});
}.bind(this));
}
componentWillUnmount () {
this.unsubscribe();
}
This is some code I have in a tab page component. These tab pages get swapped in and out in a parent component as the user changes tabs to display different data. I have stepped through the debugger and confirmed that as a user changes tabs, the following occurs in order:
The previous tab is unmounted (componentWillUnmount fires and this.unsubscribe() is called. this is the previous tab component, as expected)
The new tab is mounted. (componentDidMount fires and this is the new tab component, as expected)
setState gets called in the subscribe callback with this being the PREVIOUS TAB, and react complains with an error:
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the Tab component.
This seems strange to me. Shouldn't calling unsubscribe as I have prevent this callback from being called on the unmounted component? The post that I'm following along with seems to suggest that doing what I've done should make this warning go away, and is simply questioning if this is a good idea. But in my case, it persists.
I don't think it matters, but I am using the ES6 "class" syntax whereas the original appears not to be.
subscribe(listener: () => void): Unsubscribe;
Lets read subscribe method doc.
The subscriptions are snapshotted just before every dispatch() call.
If you subscribe or unsubscribe while the listeners are being invoked,
this will not have any effect on the dispatch() that is currently in
progress. However, the next dispatch() call, whether nested or not,
will use a more recent snapshot of the subscription list.
Since you first have called dispatch method, all listeners are invoken and your unsubsribe call will only take place on next dispatch call.

Resources