Api call in render method of reactjs - 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.

Related

How to call a function from all components' componentDidMount

I'm building a ReactJS based website. I'm using hooks if it makes a difference.
I'm writing some security code for anti forgery token etc. I would like to call a function automatically without implementing it page by page.
How to call a function from all components' componentDidMount? Is there a global event for it?
Right now doing this like this; but it is really complicated to follow all and implement this...
componentDidMount() {
token.Get();
}
If you are using Hooks, you are using function components, and therefore do not have access to lifecycle methods like componentDidMount. To trigger an effect on mount and unmount, you would have to do something like
React.useEffect(() => token.Get(), [])
(https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects)
To define a global behaviour as you seem to want, you may be able to implement the behaviour at the root App.js level. You could also possibly create a higher order component to wrap every component that needs this behaviour, but it seems overkill for one line of code (https://reactjs.org/docs/higher-order-components.html)
If you want to automatically add a token to all your requests, it's easy to do so with axios like this:
axios.defaults.headers.common['Authorization'] = YOUR_TOKEN;
See axios documentation for details.

Simultaneous async API calls in react hooks

I've been using hooks in my React project for a while now and have developed a hook for getting data, similar to many others, which I use like this.
const [callApi, isLoading, result, errrors] = useData();
callApi is a function which you call with your data and axios config, it makes the API call and updates the other variables. I deal with the result in a useEffect() call which sets the state when it receives new data. It's fairly simple.
The problem is that while it works very well for one request at a time, it has a single isLoading state and a single result state, which is no good if it's called before the previous call is finished. Let's say my user sending a message to his friends and the UI shows a list of friends with a "send message" button next to each name, they might click 3 buttons and make 3 calls in quick succession. We then have a race condition to see which one sets the result first.
I'm used to imperative programming with promises, in my old Angular code the button click would call an event handler which would call the api and the promise .then() would then deal with the result. This could happen 100 times simultaneously and each one would resolve seperately and then update the UI.
So my question is, is there an idiomatic way of doing this declaratively using react hooks so that I can fire off multiple requests and deal with the loading/result/errors separately?

Correct pattern for recursive api call in react redux-thunk

We want to make a recursive API call based on the number of records received in the response.
For example, if the number of records we get is 10 and the total records are 20, we need to call to the same API again with an updated marker (i.e., we are making calls to next 10 records).
So, what should be the correct pattern to call the API again? Should I do a .then() to the first dispatch(it is inside componentDidMount method) or should I call the API again instead of dispatching the first response.
Though the first option works but it would cause the render method to be called multiple times and I am not sure if that is the correct pattern or not.
componentDidMount() {
store.dispatch(getCustomerData('1234',1,10)).then((res) => {
//do some login and call store.dispatch(getCustomerData('1234',2,10)) again
})
}
OK, so based on on your comments I would suggest to just call one function in your componentDidMount and call your api inside this function. After getting response you can check if there is more data and call your api again for the other datas. Like you said using .then() will do the work.
I hope I explained myself clearly, if not please say it so I can describe it with more detail.

componentDidMount() on reloading component

I have components A and B, both of which have their own componentDidMount() methods. Think of them as two separate modules that are NOT loaded together. It's either A or B but not together.
My simple question is this:
If I hit component A, then B, then back to A, will componentDidMount() in component A be called on the second one?
When I read the documentation, it states that componentDidMount() is called only once and componentDidUpdate() is called in all component updates but I'm not 100% clear if this is happening in the entire life cycle of my app.
I'm trying to figure out the logic for API calls. I may or may not need to make an API call for component A again so I have some logic that handles that. Just trying to make my logic work for making that call.
So, the question simply is, will I hit componentDidMount() in component A on subsequent loads during a user's session? A user session may last a long time during which the user may come back to both component A and B many a times.
The answer is yes, every time you switch components you call again for componentDidMount().
More about that here - https://reactjs.org/docs/react-component.html
The logic for API calls in React itself is most like:
Create container which call for API in componentDidMount method.
Create external dumb components which are imported to the container, call them in the render() method and pass the data via props
Create logic which is executing which component should you call now( react-router-dom library is also good approach for conditional rendering)
I hope I explained you that a bit. feel free to ask some questions!

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