ReactJS - Javascript try/catch shows an error in the console - javascript

I'm pretty new on React and I'm learning this language nowadays.
For this purpose I'm building a test project on which I try to encounter the main classical issues and looking to solve it.
For most of React developpers, there are no difficulties in following code but I will give a few details for better comprenhension.
I have a portion of javascript code that is returning a list of articles from a Symfony Backend API only if user is authorized for getting it (Authorization via JWT will be done later). A getArticles function returns a Promise that tries to get the articles from the Symfony backend inside a try {} catch (error) {} block.
Voluntarily, Authorization token is not send to trigger an error in the query.
As the axios.get is located inside a try {} catch (error) {} block, I am surprised that an error appears in the console for the request. It doesn't impact the behavior but it is not very clean to have these errors in the console.
My question(s) :
Why an error appears in the console while the code is inside a try/catch ? To get a cleaner app behavior, is there a way to avoid having this error in the console ? I have found other React try/catch issues but I didn't deduct the similarity with my issue. Am I missing something ?
Thanks in advance ;-)
I am aware that my code could be refactored, do not hesitate to suggest any good practice
componentDidMount(){
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => {
return req;
});
const getArticles = async() => { return new Promise( (resolve, reject)=> {
try{
const data = axios.get('https://xxxxx/api/articles');
resolve(data);
} catch (err) {
reject(err);
}
});
}
getArticles().then(res => {
const articles = res.data.data.items;
this.setState( {errorOnArticlesLoading:false, articles: articles } );
})
.catch(error => {
this.setState( {errorOnArticlesLoading:true} );
});
}

You can try in this way and Async functions itself returns a promise, you don't need to return a new Promise manually.
async componentDidMount() {
try {
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => req);
const getArticles = async () => {
try {
const data = axios.get('https://xxxxx/api/articles');
this.setState({ errorOnArticlesLoading: false, articles: data.data.items });
} catch (err) {
this.setState( {errorOnArticlesLoading:true} );
}
};
await getArticles()
} catch(err) {
console.log('Handled root error')
}
}

It seems that there are no solutions to avoid the 401 http error code in the console because it it printed by Chrome itself: See discussion here. So the following code cannot avoid the 401 error status to be printed in the console.
componentDidMount(){
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => {
return req;
});
const getArticles = async() => {
const data = await axios.get('https://xxxx/api/articles');
return data;
}
getArticles().then(res => {
const articles = res.data.data.items;
this.setState( {errorOnArticlesLoading:false, articles: articles } );
})
.catch(error => {
this.setState( {errorOnArticlesLoading:true} );
});
}

Related

Exception handling in promise chain

I have a code with multiple promise chain as shown below
.then(function(response) {
//my code
})
.then(function(app) {
//my code
})
.then(function() {
//my code
})
Have added exception handling to each of them as shown below so that if one breaks the rest chain continues.
Is this the correct way of handling exception for multiple chain blocks, or any best practice can be followed to handle the exceptions so that the code execution doesn't break if one fails.
.then(function(response) {
//my code
})
.catch(e => {})
.then(function(app) {
//my code
})
.catch(e => {})
.then(function() {
//my code
})
.catch(e => {})
If your code can accommodate the error (whatever it is) that's occurring early on, this can be a reasonable way of doing it, but I'd always have to look twice at it in a code review because it's fairly unusual for the code to be able to just ignore errors like that. The code is roughly equivalent to:
try {
//my code
} catch (e) {
}
try {
//my code
} catch(e) {
}
try {
//my code
} catch(e) {
}
...but using promises instead. So it's a bit suspect, but can be correct, for the same reasons the above is a bit suspect but can be correct if you need to do a series of things, one at a time, and have each of them done even if the previous one fails.
Beware that it means app in the subsequent fulfillment handler will be undefined:
.then(function(response) {
//my code
})
.catch(e => {})
.then(function(app) { // <=== `app` is `undefined` here
//my code
})
.catch(e => {})
.then(function() {
//my code
})
.catch(e => {})
Answer posted before, is correct.
I just want to insert my 2 cents.
You can have some fun with one helper function (or use something more fancy like whole Either monad thingy from fp-ts package)
const run = async (fn) => {
try {
const result = await fn()
return [result, null]
} catch (err) {
return [null, err]
}
}
and write code without try\catch or .then\.catch
const [response, error] = await run(() => fetch('asdfasdf'))
const app = buildApp(response.ok ? await response.json() : { fallback: 'data' })
const [appResponse, appError] = await run(async () => {
await app.compileTemplate()
return app.buildResponse()
})
if (appResponse) {
// ...
}
Or more useless approach, you can throw a custom error, so your first .catch block will be able to do something.
class AppFromResponseError extends Error {
constructor(message, fallbackApp) {
super(message)
this.name = "ResponseError"
this.app = "fallbackApp"
}
}
builder
.then(function(response) {
if (response.ok !== true)
throw new AppFromResponseError('not ok', minimalApp)
})
.catch(e => {
if (e.app) return e.app
})
.then(app => { /* some kind of app will be here */})

Redux-Thunk: async dispatch is not working

I am trying to build an app in react native that is suppose to take take two inputs by a user and then make a query to an api and get information about the two inputs. I have been having trouble with redux and redux-thunk and specifically with async actions.
This is the code in my app that i am specifically having trouble with
export const fetchData = url => {
console.log("start Fetching");
return async dispatch => { // this is where the problem is
dispatch(fetchingRequest());
try {
const response = await fetch("https://randomuser.me/api/?results=10");
const json = await response.text();
if (response.ok) {
dispatch(fetchingSuccess(json));
console.log("JSON", json);
} else {
console.log("fetch did not resolve");
}
} catch (error) {
dispatch(fetchingFailure(error));
}
};
console.log("Fetched data");
};
Upon debugging the function, I have ended with finding that when the fetchData function is called the function will execute but the async dispatch that is being returned has undefined behavior.
The output in the debugger when the function is called should be
start Fetching
JSON file information/Error
but the output in the debugger is actually
start Fetching
Why not simply using Promise syntax?
fetch("https://randomuser.me/api/?results=10")
.then(response => {
if (response.ok) {
// do something
}
})
.catch(e => console.log('fetch did not resolve'));

getting value from a chained promises

im really new to this of promises and im getting headaches trying to understand this, so now im trying to get an answer from a method that returns a promise, then i catch the value in a conditional and make some other operations
let addService = async(req, res) => {
checkCategoryExists(param).then(result => {
if(result){
// code here
}
}).catch(err => console.log(err));
}
let checkCategoryExists = async(param) => {
let docs = db.collection(collectionName).doc(param);
docs.get()
.then(categoryDoc => {
if(categoryDoc.exists){
if(categoryDoc.data().param== param){
return true;
}
} else {
return false;
}
})
.catch(err => false);
}
the method "checkCategoryExists" is a query to a firestore db. When i tried to check if result variable is true or false, it happens to be undefined. its not with ".then()" that i get to catch the value from the returned promise? if someone can help me, thanks in advance
So as mentioned above I think your issue is based on not returning the results of your document search so both examples below handle that.
I also noticed that you were using async tags on your functions but not ever using await so I wanted to give examples of both ways of doing it in case you wanted to use Async/Await but weren't certain how.
In the promise chain example I'm relying on the syntax of arrow functions to create the returns (no {} means return right side of equation) since none of your given code requires data manipulation before return (if your actual code needs that you should of course use brackets and remember your return statement :D )
If you choose to use Async/Await you can structure the code much more closely to synchronous examples and use try catch statements. Sometimes I find this syntax more clear if I have to do a lot of processing/manipulation before returning a result.
Good Luck :)!
// Promise Chains
const addService = (req, res) =>
checkCategoryExists(param)
.then(result => /* do stuff */)
.catch(err => console.error(err.message));
const checkCategoryExists = param =>
db.collection(collectionName.doc(param)
.get()
.then(categoryDoc =>
Promise.resolve((categoryDoc.exists && categoryDoc.data().param === param))
);
// OR using Async/Await
const addService async (req, res) => {
try {
const catExists = await checkCategoryExists(param);
if (!catExists) {
throw new Error('error code');
}
// Do Stuff.
} catch (error) {
console.error(error);
}
};
const checkCategoryExists = async param => {
try {
const docs = await db.collection(collectionName)
.doc(param)
.get();
return (docs.exists && docs.data().param === param);
} catch (error) {
console.error(error)
}
}

JS: Catch network error and return default response data

I am developing an app that uses promises to communicate with an remote API. This app needs to be able to work offline seamlessly, so I need to handle network errors. Since I can define some default data upfront that is good enough to keep the app functioning. My approach is to catch the error and return a new promise loaded with the default data:
API.js
function getDataFromAPI(id) {
return axios.get(`${BASE_URL}/${id}`)
.then(response => response.data)
.catch((error) => {
// Only return fake data in cases of connection issues
if (error.message == 'Network error') {
const fakeResponse = {myDefaultData: 'default data all over the place'};
// receiving function expects data in promise-form
return Promise.resolve(fakeResponse);
}
});
}
Action.js using the API
needSomeData = () => {
api.getDataFromAPI().then((response) => {
// Data is processed/used here
}));
The code sample works but I am not sure if this is a good/clean approach? Would it be better to handle this in a service worker? Or should I use an entirely different way to approach the issue?
so you can clean it a little bit more.
since any return from .catch consider the value of the next resolved promise. you do not need to return Promise.resolve(value) return value are enough
function getDataFromAPI(id) {
return axios.get(`${BASE_URL}/${id}`)
.then(response => response.data)
.catch((error) => {
// Only return fake data in cases of connection issues
if (error.message == 'Network error') {
return {
myDefaultData: 'default data all over the place'
};
else {
return 'return something or throw new exception'
}
});
}
So for whom that want to know exactly how Promise algorithm behave
Promises/A+ specification
In fact I find It very interesting

this await throwing unexpected token error

I have a simple async function. It just sends a request and returns the data:
export const updatePanorama = async ({ commit }, payload) => {
const urlEnd = '/v1/pano/update'
const type = 'post'
const resp = await api.asyncRequest(urlEnd, type, payload)
commit('SET_PANORAMA', resp.data)
return resp
}
And this is how I'm using the function:
handleUpdatePanorama (panorama) {
const payload = {}
this.updatePanorama(payload).then(resp => {
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
}).catch(() => {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
},
The problem is, the code after catch runs if there's an error inside then. But this way I don't know whether the catch error is an request error or and error triggered by the code inside then.
I'm trying try and catch to solve that problem:
handleUpdatePanorama (panorama) {
try {
const payload = {}
const resp = await this.updatePanorama(payload)
console.log('resp:', resp)
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
} catch (err) {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
},
However, I get an unexpected token error in this line: await this.updatePanorama(payload)
What am I doing wrong?
The problem is, the code after catch runs if there's an error inside then
The solution for that is to not use catch, but the second then parameter. Have a look at the difference between .then(…).catch(…) and .then(…, …) for details.
I'm trying try and catch to solve that problem
That won't work, the catch clause will still be called if there's an exception thrown by setIsLoading or handleAlert.
I get an unexpected token error. What am I doing wrong?
You have not declared the handleUpdatePanorama method as async.
To mitigate the issues and fix the syntax, you could write
async handleUpdatePanorama (panorama) {
var result
try {
const payload = {}
const resp = await this.updatePanorama(payload)
console.log('resp:', resp)
result = ['updateSuccess', 'success']
} catch (err) {
result = ['updateError', 'danger']
} finally {
this.setIsLoading(false)
}
this.handleAlert(...result)
},
If you need to handle errors specifically from updatePanorama, use the second argument to .then(onSuccess, onError)
handleUpdatePanorama(panorama) {
const payload = {}
this.updatePanorama(payload).then(resp => {
this.setIsLoading(false)
this.handleAlert('updateSuccess', 'success')
}, err => {
// handle error from updatePanorama
// you can throw err if you also want to handle the error in .catch()
}).catch(() => {
this.setIsLoading(false)
this.handleAlert('updateError', 'danger')
})
}
note: if you return (or have no return statement) from the error handler, any subsequent .then(onSuccess will execute, if you throw an error (or return Promise.reject() for example, then the .catch() code will also run

Categories

Resources