Existing code(Working fine) :
.then((result) => {
this.triggerAction(result.id);
}).catch((error) => {
this.errorMsg(error);
});
when i try to add condition inside the .then throws error.
.then((result && result.id) => {
this.triggerAction(result.id);
}).catch((error) => {
this.errorMsg(error);
});
I need to check both result and result.id is coming in the response and throws error id if not available in the result .
To throw an error if result.id is missing, you should do the following:
.then((result) => {
if(!result.id) {
throw new Error("result.id is missing!");
}
this.triggerAction(result.id);
}).catch((error) => {
this.errorMsg(error);
});
You can also do throw result if you just want to pass result to the .catch() block
.then((result) => {
result?.id && this.triggerAction(result.id);
})
.catch((error) => {
this.errorMsg(error);
});
result inside .then is the response you receive on success. You can't apply condition on the fly inside function parameters. You have to check inside the callback function. If results will have id (result?.id) then this.triggerAction(result.id) will invoke
I hope it will work.
Thanks :)
Related
how can I make a second request if .catch on promise is executed , in order to get the data successfully
because if .catch is executed I did not received the data. and I have to refresh the page again to get the data.
fetch("https://randomuser.me/api")
.then(result => result.json())
.then(data => {
console.log(data)
})
.catch(error => console.log(error))
You just want to retry in the catch? You will need to call the function that makes the request again. This is called recursion. Ie:
function makeRequest() {
fetch("https://randomuser.me/api")
.then((result) => result.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
return makeRequest(); // Calls itself recursively
});
}
However this introduces the possibility of an infinite loop, so you need some way to break out, maybe like this:
function makeRequest(attempt=0) {
const maxRetries = 3;
if (attempt > maxRetries) {
throw new Error(`Could not fetch user after ${attempt} attempts`);
}
fetch("https://randomuser.me/api")
.then((result) => result.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log(error);
// Call self and increment the attempt number.
// Very important to ensure that the break condition
// can be met or we can end up calling the function
// forever with no way to escape. This is called an
// infinite loop.
return makeRequest(attempt + 1);
});
}
You can also make the logic more complex for retries, like introduce a timeout before the next request if attempt is gt 0, add exponential backoff etc.
Always remember to be careful of infinite loops when using recursive functions.
You can put the fetch and .json() calls into a function, then call that function once (immediately), and call it again inside the .catch if needed:
const getData = () => fetch("https://randomuser.me/api")
.then(result => result.json())
getData()
.then(console.log)
.catch((error) => {
console.log(error);
return getData();
});
.catch((error2) => {
// Could not get response after 2 attempts
console.log(error2);
});
I'm having some trouble understanding what I'm doing wrong. I have a function that receives a url to which should make a GET request, in case of success should fill a combo with the received data (this depends which function calls it), in case of fail it should execute some common code.
getFirstCombo = () => {
this.getFromApi('/First/GetAll')
.then(data => this.setState({firstComboOptions: this.parseCombo(data)}))
.catch(error => console.log('ERROR2: ', error));
}
getSecondCombo = () => {
this.getFromApi('/Second/GetAll')
.then(data => this.setState({secondComboOptions: this.parseCombo(data)}))
.catch(error => console.log('ERROR2: ', error));
}
parseCombo = (data: any) => {
const combo = data.map(item => (
{ label: item.description, value: item.id }
));
return combo;
}
getFromApi = (url: string) : Promise<any> => {
return restApiAxios.get(url)
.then(response => {
return response.data;
})
.catch(error => {
console.log('ERROR: ', error);
});
}
this code is executed on the componentDidMount of the react component, but when it fails, it first prints :
ERROR: Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:83)
and immediately after:
PanelDatos.tsx:50 ERROR2: TypeError: Cannot read property 'map' of undefined
at PanelDatos.parseCombo (PanelDatos.tsx:55)
at PanelDatos.tsx:50
so, when failing executes the catch block from getFromApi and then it tries to execute the then block in getFirstCombo, which triggers the catch block from the same function cause data does not exist, why is that? shouldnt it just execute the first catch?
thanks in advance
.catch returns a promise much like .then, allowing you to return a custom value and handle it that way.
Try doing the following to observe the effect:
Promise
.reject(1)
.catch(e => e) // Catch the error and return it
.then(console.log) // will log 1 to the console
This means you'll need to add some checks if you want to continue to use promises like this:
Promise
.reject(new Error('haha'))
.catch(err => ({err}))
.then(({err, data}) => {
if(err) return // Do nothing
// enter code here
})
However, using async / await will improve readability even more:
getFirstCombo = async () => {
let response
try {
response = await this.getFromApi('/First/GetAll')
} catch (e) {
return // Exit early
}
let parsed
try {
parsed = this.parseCombo(data)
} catch (e) {
console.log(e)
return // Exit early
}
return this.setState({firstComboOptions: parsed})
}
And, of course, throw the error again in your catch block in your api to allow it to handle api calls.
This is happening since inside getFromApi catch method on the error you are not returning anything, so by default, it is returning a resolved promise with null response and the execution goes inside getFirstCombo then method, causing another error. You can update your code to resolve this like:
getFromApi = (url: string): Promise<any> => {
return restApiAxios.get(url)
.then(response => response.data)
.catch(error => Promise.reject(error));
}
The static Promise.reject function returns a Promise that is rejected. So, it will go directly into catch of wherever getFromApi is called.
DEMO:
async function getFromApi(url) {
return fetch(url) // rejects
.then(response => response.json())
.catch(err => Promise.reject(err))
}
async function getFirstCombo() {
getFromApi('https://no-such-server.abcd')
.then(data => console.log('data: ', data))
.catch(error => console.log('ERROR2: ', error));
}
getFirstCombo()
DEMO #2 (With getFirstCombo function not having any catch block) :
async function getFromApi(url) {
return fetch(url) // rejects
.then(response => response.json())
.catch(err => {
console.log('ERROR in getFromApi(): ', err);
return null; // return null, empty array, 0 or false... as per your requirement
})
}
async function getFirstCombo() {
getFromApi('https://no-such-server.abcd')
.then(data => console.log('data: ', data))
// Same value set in catch block of getFromApi will return in this then() block
// Validate this `data` variable before processing it further like:
// if(data === null) this means an error had occurred
// else continue with your logic
}
getFirstCombo()
I´m pretty new to Promises and found many examples here how to access the actual value which is always done with console.log. But my goal is to store the result in a variable and work with it.
getdata = () =>
fetch(
"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&outputsize=full&apikey=demo"
)
.then(response => {
if (response.status === 200) {
return response.json();
} else {
throw new Error("This is an error");
}
})
.then(data => {
console.log(data);
});
getdata();
This code works. Can you help me to rewrite it that the getdata() function allows me to store the result in a variable. Return does not work since I will receive another pending Promise.
You can do it like this:
getdata = () =>
fetch(
"https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&outputsize=full&apikey=demo"
).then(response => {
if (response.status === 200) {
return response.json();
} else {
throw new Error("This is an error");
}
});
getdata().then(data => {
//I can do whatever with data
});
Of course you would also want to handle the scenario where the request failed, so you could also chain a .catch(). Alternately, if you have your build process configured for it, you can use async and await so you could do:
try {
const data = await getdata();
} catch(err) {
}
This would need to be in a function marked as async
Well at first we need to declare a variable let's say temp. Then use fetch API to request our query with URL. If server status is 200 then it will return a promise, we need to use then method by passing any argument (res, response, r anything...) and then a fat arrow function (=>) so that we can make the response as json format. After then we need to use another then method to return the json output and assign the value to our declared temp variable.
But if there is any error like 500, 400, 404 server error we need to use catch method with err argument and console it out.
let temp;
fetch('https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol=MSFT&outputsize=full&apikey=demo')
.then(res => res.json())
.then(data => temp = data)
.catch(err => console.log(err));
I've looked through a few posts such as this post
I want to use a console.log to see if I successfully set an item to AsyncStorage.
Here is my code:
export function saveDeckTitleAPI(key,title) {
return AsyncStorage.setItem(uuid(), JSON.stringify(new DeckCreator(title)))
.then(data => {
debugger;
console.log('INSIDE SET ITEM');
AsyncStorage.getItem(data.key).then(item => {
console.log(item);
})
})
.catch(err => {
console.err(err);
});
}
When I run this code, the .then and the .catch aren't fulfilled. I tried logging the promise by itself, and I get a similar result as the post above.
Do I have to use async/await? Is that the problem here? Here are the docs to setItem.
You can pass a callback as the third argument. If there's an error, it will be the callback's first parameter. If there's no error, console log that all is well and good, otherwise log the error.
Yes you need async and await
You can get an inspiration from the code below, the way I do a facebook login with setItem
const doFacebookLogin = async dispatch => {
const { type, token } = await
Facebook.logInWithReadPermissionsAsync('xxxx', {
permissions: ['public_profile']
});
if (type === 'cancel') {
return dispatch({ type: FACEBOOK_LOGIN_FAIL });
}
await AsyncStorage.setItem('fb_token', token);
dispatch({ type: FACEBOOK_LOGIN_SUCCESS, payload: token });
};
I need access to responseA to get access to a field value further along the chained request. How can that be done elegantly?
axios.get(`/endpoint`)
.then((responseA) => {
// Do something with responseA
return axios.put(signedUrl, file, options);
})
.then((responseB) => {
// Do something with responseA & responseB
})
.catch((err) => {
console.log(err.message);
});
UPDATE: I should probably mention that in my first .then() I return another network request. And it has to happen in sequence.
What is happening inside the first .then() block? In theory, you could return the values you need from responseA to the second .then() block, as whatever you return from the first then block will be available as responseB. In other words, it would look something like this:
axios.get(`/endpoint`)
.then((responseA) => {
// additional request/logic
const moreData = someFunction()
return { responseAdata: responseA.dataYouWant, moreData: moreData }
})
.then((responseB) => {
// now responseA values will be available here as well, e.g.
responseB.responseAdata
// Do something with responseA & responseB
})
.catch((err) => {
console.log(err.message);
});
You have a number of options to do this.
1) Break the chain
let promiseA = axios.get(`/endpoint`)
let promiseB = promiseA.then((responseA) => {
// Do something with responseA
})
return Promise.all([promiseA, promiseB]).then(function([responseA, responseB]) {
// Do what you must
});
2) Use await
let responseA = await axios.get('/endpoint/')
// You can figure out the rest
You can use Promise.all:
axios.get(`/endpoint`)
.then(
responseA =>
Promise.all([
responseA,
axios.get("/endpointB")
])
)
.then(
([responseA,responseB]) => {
console.log(responseA,responseB);
})
.catch((err) => {
console.log(err.message);
});
If anyone is still facing problem then try as below :
axios.get('https://api.openweathermap.org/geo/1.0/direct?q=' + req.body.city + '&limit=1&appid=e43ace140d2d7bd6108f3458e8f5c')
.then(
(response1) => {
let output = response1.data;
axios.get('https://api.openweathermap.org/data/2.5/weather?lat=' + output[0].lat + '&lon=' + output[0].lon + '&appid=e43ace1d1640d2d7bd61058e8f5c')
.then((weatherdd) => {
res.render('index.twig', { weatherdata: weatherdd.data, cityname: req.body.city, todaydatex: todayDate });
})
}
)
.catch(
err => {
res.send(err)
}
);
Hint: As You can see I am using response1 which is returned from the first request and then defined a local variable with output and finally using the data in my next HTTP request (eg: output[0].lat)