Why there are 2 then blocks in fetch call in React? - reactjs

I am using fetch api to bring data from back-end and it is working as expected for me. However I am not able to figure out why there is a need of 2 then blocks in fetch call.

Fetch API uses promises and it takes a request as a parameter and return a promise that resolve to a Response Object that response object has information about the server response like status code and headers and the body of the response which is the data you want , and some of the methods on that Response Object return Promise too so you need to make another then block , methods like response.json() response.text() response.blob() , so this is why you need to then blocks , the first resolve the response from the server and the second get the data from the response .
learn more
Fetch API
javascript Promise
Using Fetch API

Fetch returns Promise (Easy article of Promise) and you need to resolve promise to access data. To resolve a promise, you need to use then()
A basic fetch example:
fetch('https://jsonplaceholder.typicode.com/todos')
.then(response => response.json())
.then(data => console.log(data, 'Data'));
In the above example, fetch returns promise, so it is resolved in
first then() where it is getting response object that is
representation of the entire HTTP response. So to extract the JSON
body content from the Response object, we need to use the json()
method, which returns a second promise that resolves with the result
of parsing the response body text as JSON. Click here for More
Detail
Here I run a fetch using online js compiler and show the output in console. Please have a look at description in the picture.

Without seeing your code, I assume the promise being returned and reconciled in the first "then" block has another asynchronous call with it's own return. For instance...
foo() //returns a promise
.then(() => { // called when "foo" resolves the promise
return bar();
})
.then(() => { // called when "bar" resolves the promise
})
.catch((err) => { //errors
});
If the first "then" block isn't returning another promise, I don't think the 2nd block will be called.

Related

Getting json data from url

How do I get a JSON response from URL?
In my case, the URL is https://api.mathjs.org/v4/?expr=2*2 JSON response and then whenever someone types !test it sends the json/data from the URL.
Here is some sample code using node-fetch, I cant guarantee it will work well
const fetch = require('node-fetch')
(async () => {
const response = await fetch(`https://api.mathjs.org/v4/?expr=${encodeURIComponent(2*2)}`).then(r => r.text())
console.log(response)
})()
this logs 4.
this is a sample code as i said,
you would have to modify it to your needs, i used a iife as fetch method returns a promise
you can do:
<message>.channel.send(`the result is ${response}`)
as a example adapted from the above given code
ps: rather than using a api for math you could use mathjs package (which your using, just its the api version)
Edited: forgot of encodeURIComponent in fetch request url, or you will get a Only absolute URLs are supported error
You don't need JSON just to get the value of the query parameter from the URL. If you just need to get the number you can try it with URLSearchParams:
console.log(window.location.search); //output: '?expr=2*2'
var params = new URLSearchParams('?expr=2*2');
console.log(params.has('expr')); //output: 'true';
console.log(params.get('expr')); //output: '2*2';
you get the value from params.get('expr'));

I am not able to set the state of locg variable from the Google api. I need to fetch multiple location latitude and longitude from the Google API

state={locg:''}
componentDidMount(){
fetch('https://maps.googleapis.com/maps/api/geocode/json?address=TajMehal&key=xxxx').then(
response=>response.json()).then
(json=>this.setState({locg:json}));
console.log('Locations from Google wdw',this.state.locg)
}
I need to create array of latitude and longitude.But for above code itself not working for hardcoded area.locg is null
The reason why you are not seeing the result on the console is because the fetch method is asynchronous. Meaning, your console log gets executed first even though it is at the end because the fetch method takes more time to finish. And since it is asynchronous, console log does not have to wait for the fetch to finish executing.
So to address this, you must use async/await. The word async before a function means one simple thing: a function always returns a promise. And the keyword await makes JavaScript wait until that promise (fetch method) settles and returns its result. This is how it should look like:
async componentDidMount() {
await fetch('https://maps.googleapis.com/maps/api/geocode/json?address=TajMehal&key=YOUR_API_KEY')
.then(response=>response.json())
.then(json=>{
this.setState({locg:json});
console.log('Locations from Google wdw',this.state.locg);
});
console.log(this.state.locg)
}
Here is a working sample for your reference: https://stackblitz.com/edit/react-async-await-63982740

Unable to figure out what's happening here in $http.get - Angular

I'm a newbie to Angular JS. I was referring Online tutorials and came across the $http service.
(function () {
"use strict";
angular
.module("ngClassifieds") // referring module which is already created
.controller("classifiedsCtrl", function ($scope, $http) {
$http.get('data/classifieds.json')
.then(function(classifieds){
$scope.classifieds = classifieds.data;
})
});
})();
In this piece of code, I'm not able to figure out these lines. Can
anyone explain what actually happens here ?
$http.get('data/classifieds.json')
.then(function(classifieds){
$scope.classifieds = classifieds.data;
}
I have this data in my data/classifieds.json file.
My question is, what exactly the data referred in classifieds.data is ?
what does classifieds.data represent here ?
what information does it contain?
what would be the result which we assign to $scope.classifieds?
$http returns a promise, it's an asynchronous call, angular use a fork of a library called Q for promises, you can see $q documentation here: https://docs.angularjs.org/api/ng/service/$q.
When the promise is fulfilled, that means, the asynchronous call is complete, the .then method call success or error callback depending on the result of the async call.
.then(successCallback, [errorCallback], [notifyCallback]) – regardless
of when the promise was or will be resolved or rejected, then calls
one of the success or error callbacks asynchronously as soon as the
result is available. The callbacks are called with a single argument:
the result or rejection reason. Additionally, the notify callback may
be called zero or more times to provide a progress indication, before
the promise is resolved or rejected.
The argument passed to the success callback is an object with the information about the request response. The data property contain the body of the response, in other way, all the content of data/classifieds.json file (in your case), therefore, $scope.classifieds will contain the json returned by data/classifieds.json.
Here a friendly article about promises and $q: http://www.dwmkerr.com/promises-in-angularjs-the-definitive-guide/
A simple get request example from AngularJS Docs.
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
In your code,
$http.get('data/classifieds.json') // This is the URI of your json file
.then(function(classifieds){ // Success callback
$scope.classifieds = classifieds.data; // Here, you are assigning response's data into $scope.classifieds
}

Angular $http.reject vs. $q.reject

I am remember researching this awhile back and coming up empty handed and I still can't find any good info on this - why does there appear to be a $q.reject method but not an $http.reject method?
For example, in real life we might have:
unfollow: function (userId) {
if (!AuthService.isLoggedIn()) {
//$location.url('/login');
window.location.href = '/login';
return $q.reject({error: 'no logged-in user, but non-existent user could still click a follow button?'});
}
else {
return $http({
method: 'PUT',
url: ConfigService.api.baseUrl + '/v1/users/add_unfollow/by_id/' + userId
});
}
}
I would rather uses the relevant $http.reject instead of $q.reject, but that doesn't seem to work.
Since $http returns a promise in one leg of the conditional...the function itself needs to return a promise in the other leg also.
Using $q.reject() is simply a shortcut to return a rejected promise.
Without it, any place that calls unfollow().then() wouldn't have a then() method if a promise wasn't returned
$http would wrap the http calls and return a promise. The promise would rejected if the actual http request is failed, and adding a reject method would not make much sense, rather it should be in the promise.
In your example you would not even need to call the $http service to reject the request.

Return multiple data independent resource promises

Via this link I've found an example of returning multiple resource promises (lines 44-52):
http://embed.plnkr.co/LZad4ZyEYjrbKiTPbAwu/script.js
var GistsData = Gists.query();
var MetaData = Meta.get();
GistsData.$promise.then(function(response) {console.log('Resource 1 data loaded!')});
MetaData.$promise.then(function(response) {console.log('Resource 2 data loaded!')});
return $q.all([GistsData.$promise, MetaData.$promise]);
In my case the second resource API call (MetaData) is dependent on a specific value that is returned by the first resource API call (GistsData).
I try to figure out how I can use a value that is returned by GistData (for example an ID) in the MetaData resource? Like this:
var MetaData = Meta.get({ id : GistsData.id });
I want to return a promise after the MetaData with the ID has returned a promise.
Thank you
Firstly I suggest you do a little more reading about promises, as they are awesome :)
As for your question, what you want to do is promise chaining. Notice how you are utilising the .then() functions for each of the resource promises. then() gets called once the promise has resolved, which in your case is when the queries have returned.
So instead of running each one independently, use the then() function of the first promise to then begin running the second. For example:
return Gists.query().$promise.then(function(response){
// Gists has finished and the data it returned is in response
// Now run your second query, using the response from the first
return Meta.get({ id : response.id }).$promise.then(function(nextResponse){
// Now nextResponse will contain the result of Meta.get(), having used the id that returned from the first response
console.log(nextResponse);
});
});
Now there are nicer ways to write the above, but hopefully it explains chaining enough for you.

Resources