When my component mount I need to request it content from an API. In the docs:
componentDidMount() is invoked immediately after a component is
mounted. 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.
and it follows:
Calling setState() in this method will trigger an extra rendering (...)
Use this pattern with caution
because it often causes performance issues.
What is the best practice to make a request to an API and, immediately, setState with the response?
The best way to call an API and update the state after you receive the response is in componentDidMount() or componentWillMount().
Which one might depend on what you want to do with your data from your API-call. If you need to access your components DOM then componentDidMount() must be used. That said, neither of these will save you from an additional re-render, unless your data doesn't need to be set to your state, in which case you can just save it to this.
The official documentation even states this, in this section:
componentDidMount() is invoked immediately after a component is mounted. 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.
Before Rendering to call api:
componentWillMount(){
fetch(api)
.then((response)=>{
this.setState({data:response.data});
})
}
After Rendering to call api:
componentDidMount(){
fetch(api)
.then((response)=>{
this.setState({data:response.data});
})}
Before Rendering to call props data:
componentWillReceiveProps(){
this.setState({data:this.props.data});
}
Whenever you trigger setState your component is going to be re-rendered (regardless the lifecycle event).
Use this pattern with caution...
You can get to an endless loop for example if you trigger setState in componentWillReceiveProps and you are not taking care of future props correctly.
My suggestion is to stick with componentDidMount and set state as soon as your api request is fulfilled:
componentDidMount() {
fetch('api-endpoint')
.then(response => response.json())
.then(result => this.setState({ stateProp: result }))
}
Related
I've recently started migrating from ngrx to ngxs and had a design question of where I should be placing some of my calls.
In NGRX, I would create 3 actions for each interaction with an api. Something like:
GetEntities - to indicate that the initial api call was made
GetEntitiesSuccess - to indicate a successful return of the data
GetEntitiesFail - to indicate a unsuccessful return of the data
I would create an effect to watch for the GetEntities Action that actually called the API and handled the response by either calling the Success/Fail actions with the resultant payload.
In NGXS, do I make the api call from the store itself when the action occurs or is there some other NGXS object that I am supposed to use to handle those API calls and then handle the actions the same way I did in ngrx (by creating multiple actions per call)?
Most of the examples I have seen, and how I have used it is to make the API call from the action handler in the state, then when the API returns patch the state immediately.
Then after the patch call, you can dispatch an action to indicate success/failure if you need to. Something like this:
#Action(GetSomeData)
loadData({ patchState, dispatch}: StateContext<MyDataModel>, {payload}: GetSomeData) {
return this.myDataService.get(payload.id)
.pipe(
tap((data) => {
patchState({ data: data});
// optionally dispatch here
dispatch(new GetDataSuccess());
})
);
}
This q/a might also be useful Ngxs - Actions/state to load data from backend
I just have implemented AJAX calls using fetch in react-native.
Implementing queuing of these AJAX calls hasn't been very well implemented.
Can any one help me?
If you want to make parallel requests, you can use the fact that fetch returns a promise to you, and then you can use Promise.all to wait for completion of all promises.
For example:
var urls = ['http://url1.net', 'http://url2.net'];
var requests = [];
urls.forEach((url)=>{
request = fetch(url); // You can also pass options or any other parameters
requests.push(request);
});
// Then, wait for all Promises to finish. They will run in parallel
Promise.all(requests).then((results) => {
// Results will hold an array with the results of each promise.
}).catch((err)=>{
// Promise.all implements a fail-fast mechanism. If a request fails, the catch method will be called immediately
});
I noticed that you added the 'multithreading' tag. It is important to notice that this code won't be doing any threading for you, as JS (generally) runs in only one thread.
I am new to angular and want to use it to send data to my app's backend. In several occasions, I have to make several http post calls that should either all succeed or all fail. This is the scenario that's causing me a headache: given two http post calls, what if one call succeeds, but the other fails? This will lead to inconsistencies in the database. I want to know if there's a way to cancel the succeeding calls if at least one call has failed. Thanks!
Without knowing more about your specific situation I would urge you to use the promise error handling if you are not already doing so. There's only one situation that I know you can cancel a promise that has been sent is by using the timeout option in the $http(look at this SO post), but you can definitely prevent future requests. What happens when you make a $http call is that it returns a promise object(look at $q here). What this does is it returns two methods that you can chain on your $http request called success and failure so it looks like $http.success({...stuff...}).error({...more stuff..}). So if you do have error handling in each of these scenarios and you get a .error, dont make the next call.
You can cancel the next requests in the chain, but the previous ones have already been sent. You need to provide the necessary backend functionality to reverse them.
If every step is dependent on the other and causes changes in your database, it might be better to do the whole process in the backend, triggered by a single "POST" request. I think it is easier to model this process synchronously, and that is easier to do in the server than in the client.
However, if you must do the post requests in the client side, you could define each request step as a separate function, and chain them via then(successCallback, errorCallback) (Nice video example here: https://egghead.io/lessons/angularjs-chained-promises).
In your case, at each step you can check if the previous one failed an take action to reverse it by using the error callback of then:
var firstStep = function(initialData){
return $http.post('/some/url', data).then(function(dataFromServer){
// Do something with the data
return {
dataNeededByNextStep: processedData,
dataNeededToReverseThisStep: moreData
}
});
};
var secondStep = function(dataFromPreviousStep){
return $http.post('/some/other/url', data).then(function(dataFromServer){
// Do something with the data
return {
dataNeededByNextStep: processedData,
dataNeededToReverseThisStep: moreData
}
}, function(){
// On error
reversePreviousStep(dataFromPreviousStep.dataNeededToReverseThisStep);
});
};
var thirdFunction = function(){ ... };
...
firstFunction(initialData).then(secondFunction)
.then(thirdFunction)
...
If any of the steps in the chain fails, it's promise would fail, and next steps will not be executed.
When to use use async false or async true in an ajax call. In terms of performance does it make any difference ?
example :
$.ajax({
url : endpoint,
type : "post",
async : false,
success : function(data) {
if (i==1){
getMetricData(data)}
else if (i==2)
{
capture = data;
}
}
});
It's not relative to performance...
You set async to false, when you need that ajax request to be completed before the browser passes to other codes:
<script>
// ...
$.ajax(... async: false ...); // Hey browser! first complete this request,
// then go for other codes
$.ajax(...); // Executed after the completion of the previous async:false request.
</script>
When async setting is set to false, a Synchronous call is made instead of an Asynchronous call.
When the async setting of the jQuery AJAX function is set to true then a jQuery Asynchronous call is made. AJAX itself means Asynchronous JavaScript and XML and hence if you make it Synchronous by setting async setting to false, it will no longer be an AJAX call.
for more information please refer this link
It is best practice to go asynchronous if you can do several things in parallel (no inter-dependencies).
If you need it to complete to continue loading the next thing you could use synchronous, but note that this option is deprecated to avoid abuse of sync:
jQuery.ajax() method's async option deprecated, what now?
In basic terms synchronous requests wait for the response to be received from the request before it allows any code processing to continue. At first this may seem like a good thing to do, but it absolutely is not.
As mentioned, while the request is in process the browser will halt execution of all script and also rendering of the UI as the JS engine of the majority of browsers is (effectively) single-threaded. This means that to your users the browser will appear unresponsive and they may even see OS-level warnings that the program is not responding and to ask them if its process should be ended. It's for this reason that synchronous JS has been deprecated and you see warnings about its use in the devtools console.
The alternative of asynchronous requests is by far the better practice and should always be used where possible. This means that you need to know how to use callbacks and/or promises in order to handle the responses to your async requests when they complete, and also how to structure your JS to work with this pattern. There are many resources already available covering this, this, for example, so I won't go into it here.
There are very few occasions where a synchronous request is necessary. In fact the only one I can think of is when making a request within the beforeunload event handler, and even then it's not guaranteed to work.
In summary. you should look to learn and employ the async pattern in all requests. Synchronous requests are now an anti-pattern which cause more issues than they generally solve.
In this PlunkerDemo, I'm trying to broadcast an event from the parent controller to child controller. However doing it directly in the parent controller won't work. The handler doesn't register the event. However doing it based on an ng-click or based on setTimeout, it works. Is it due to the scope life cycle?
http://beta.plnkr.co/edit/ZU0XNK?p=preview
See the comments of the accepted answer. They explain my problem.
Any changes to angular scope must happen within the angular framework, If any changes have to be made outside the framework we have to use the .$apply function.
$apply() is used to execute an expression in angular from outside of
the angular framework.
In your case you are triggering the $broadcast within setTimeout, where the callback gets called outside the angular framework.
So you have two solutions, either use the $timeout service provided by angular or use .$apply function.
I prefer to use the $timeout function.
var ParentCtrl = function($scope, $rootScope, $timeout){
$scope.broadcast = function(){
$rootScope.$broadcast('Sup', 'Here is a parameter');
};
$timeout(function(){
$scope.$broadcast('Sup');
}, 1000);
//this one does not work! Most likely due to scope life cycle
$scope.$broadcast('Sup');
$scope.$on('SupAgain', function(){
console.log('SupAgain got handled!');
});
};
Demo: Fiddle
Using $apply
setTimeout(function(){
$scope.$apply(function(){
$scope.$broadcast('Sup');
});
}, 1000);
A more reliable option can be to use $interval in child controller. So, instead of having significant timeout, there will be polling every small interval.
Also, instead of broadcast, use a service with a flag. Every poll will check if flag is set. When the flag is set by parent controller, the timer will be stopped during next poll. And that can indicate the event happened. The parent controller can also share data with child controller, via service.