Make Redux thunk calls synchronous for refreshing tokens - reactjs

Integrated redux with thunk middleware. On expiry of access token, refresh token api is called and on its success the first api which was not successful due to expired token is recalled again.
The refresh token api is being called and returned because it is async. and the edit api is called right away before the response of refresh token success. How do i make it synchronous so as to call the api only after the response of refresh token is received
export function editClothDetails(data, id) {
return function(dispatch, getState) {
dispatch({ type: actions.EDIT_CLOTH_REQUEST });
fetch(BASE_URL + EDIT_CLOTH_URL + `/${id}`, {
method: "PUT",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + getState().Auth.accessToken
},
body: JSON.stringify({ ...data })
})
.then(result => checkHttpStatus(result))
.then(result => checkForError(result))
.then(jsonResponse => {
dispatch({
type: actions.EDIT_CLOTH_SUCCESS,
payload: jsonResponse
});
})
.catch((error) => {
if(error.message === "Invalid token") {
//what should be the right way to make these dispatches synchronous
dispatch(refreshToken());
dispatch(editClothDetails(data, id)); //setTimeout(()=> dispatch(editClothDetails(data, id)), 100);
}
console.error("There is an error in editing cloth details !! " + error.message);
dispatch({
type: actions.EDIT_CLOTH_FAILED,
payload: error.message
});
});
};
}
export function refreshToken() {
return (dispatch, getState) => {
dispatch({ type: actions.REFRESH_TOKEN_REQUEST });
fetch(BASE_URL + '/token', {
method: "GET",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'authorization': 'Bearer ' + getState().Auth.refreshToken
},
})
.then(result => checkHttpStatus(result))
.then(result => checkForError(result))
.then(jsonResponse => {
storeLocally(constants.APP_NAME, jsonResponse);
dispatch({
type: actions.REFRESH_TOKEN_REQUEST_SUCCESS,
payload: jsonResponse
});
})
.catch((err) => {
console.error("There is an error refreshing token !!" + err.message);
dispatch({
type: actions.REFRESH_TOKEN_REQUEST_FAILED,
payload: err.message
});
});
};
}

You have to use async-await here ...
export function editClothDetails(data, id) {
return async function(dispatch, getState) { // -> see here
.catch((error) => {
if(error.message === "Invalid token") {
await dispatch(refreshToken()); //--> see here
dispatch(editClothDetails(data, id));
}
// your other code
};
}
export async function refreshToken() {. /// ---> see here
return async (dispatch, getState) => {
dispatch({ type: actions.REFRESH_TOKEN_REQUEST });
/// your other code
};
}

Related

How to present API response with redux and react

I am new to front-end. I use react and redux-form after I subbmit form on backend don't know how to handle response and present it with react. My response is simply only one number.
return function (dispatch, getState) {
dispatch({
type: CHANGE_ID_SUBMIT_DATA,
});
let reqBody = {
firstname: changeId.firstName
username: cnahgeId.userName,
};
return fetch(`${__REST_HOST__}/test/api/change/id`, {
credentials: 'include',
method: 'post',
headers: {
'Accept': 'application/json;charset=UTF-8',
'Content-Type': 'application/json;charset=UTF-8',
},
body: JSON.stringify(reqBody),
}).then(
response => dispatch(receiveData(response)),
error => dispatch({
type: CHANGE_ID_RESPONSE_ERR_DATA,
error
})
);
};
}
function receiveData(resp) {
console.log(resp.text());
return resp.text().then(response => dispatch({
type: CHANGE_ID_RESPONSE_DATA,
newId: response,
receivedAt: moment(Date.now())
}));
}```

Unhandled Rejection (TypeError): Cannot read property 'error' of undefined

I'm fairly new to React and I've been trying to create a SignUp page, however, I'm stuck in this error. Can someone give me any indication on what I should do in order to solve this error?
Signup Method:
// = Action =
// Sign up
export const signup = user => {
return fetch(
`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
}
Rewrite Signup method (ps: I only changed the .catch handler)
`
// Sign up
export const signup = user => {
return fetch(
`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => {
return response.json();
})
.catch(err =>
console.log(err));
return err;
}
`
You need to wrap up your fetch logic inside a Promise to return a value to the caller.
export const signup = user => {
return new Promise((resolve, reject) => {
fetch(`${API}/signup`,
{
method: 'POST',
headers: {
Accept:'application/json',
'Content-Type' : 'application/json'
},
body: JSON.stringify(user)
})
.then(response => response.json())
.then(jsonData => resolve(jsonData))
.catch(err => resolve({error: `something went wrong err : ${err}`}));
})
}
signup(user).then(data => {
if (data.error) {
// handle error case
} else {
// handle success case
}
})
Now your signup method will return a value. Your data variable won't be undefined anymore.
I hope it helps, feel free to add comments or ask me more details

Making Two API calls in react using axios

I am making an app where I send and receive data from one API. Once I get this data I want to make another call to the some other API sending this data to this second API and receiving data from this second API.
export const uploadImage = (data) => (dispatch) => {
dispatch({ type: UPLOAD_IMAGE });
axios({
method: 'post',
url: 'http://3.14.136.182:80/predict',
data: data,
"mimeType": "multipart/form-data",
headers: {
'content-type': 'multipart/form-data'
},
timeout: 20000
})
.then((response) => {
dispatch({ type: UPLOAD_IMAGE_SUCCESS, payload: response.data });
data = response.data;
axios({
method: 'post',
url: '3.14.136.182:8005/finalResult',
data: data,
"mimeType": "multipart/form-data",
headers: {
'content-type': 'multipart/form-data'
},
timeout: 20000
})
.then((response) => {
dispatch({ type: UPLOAD_IMAGE_SUCCESS, payload: response.data});
console.log("Mehmood",response.data);
})
.catch((error) => {
dispatch({ type: UPLOAD_IMAGE_FAILURE });
})
})
.catch((error) => {
dispatch({ type: UPLOAD_IMAGE_FAILURE });
})
}
You are missing at one return statement in you first then block. (before axios). Also you are dispatching success two times.

How to synchronize fetch method in redux action

I am wondering how I can sync my fetch method. I want to prevent rendering data in a component before a response is returned.
Here is my redux action with my fetch method:
export const FETCH_DATA_START = 'FETCH_DATA_START'
export const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS'
export const FETCH_DATA_FAILED = 'FETCH_DATA_FAILED'
export const getData = () => {
return (dispatch) => {
dispatch({
type: FETCH_DATA_START
})
fetch(baseUrl, {
credentials: "include",
method: "GET",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
})
.then(res => res.json())
.then((res) => {
dispatch({
type: FETCH_DATA_SUCCESS,
payload: res
})
})
.catch((err) => {
console.log(err)
dispatch({
type: FETCH_DATA_FAILED,
payload: 'error'
})
})
}
}
A common practice in this case is to set a flag like isFetching to true, and then display a loading spinner in your JSX based on the status of this flag.
Then when you received data, you hide this spinner and show the data.

A better way of organizing the query React Native

What if I want limit and offset to be optional? Let's say I have two actions which call this method
ProductRelatedDetail(catId, subCatId)
ProductRelatedDetail(catId,
subCatId, limit, offset)
I don't want to duplicate the function twice. What is the better and more dynamic way of managing this kind of situations?
export function ProductRelatedDetail(catId, subCatId, limit, offset) {
return function (dispatch) {
return fetch(`${constants.API}?tag=product_list&category_id=${catId}&sub_category_id=${subCatId}&limit=${limit}&offset=${offset}`, {
method: 'POST',
headers: myHeaders,
})
.then(res => res.json())
.then(data => dispatch({
type: actionType.GET_RELATED_DETAIL,
payload: data
})).catch(error => {
console.log('Got cat Feed', error);
});
}
};
I'd use an if statement as follows:
export function ProductRelatedDetail(catId, subCatId, limit, offset) {
return function (dispatch) {
if(!limit && !offset){
return fetch(`${constants.API}?tag=product_list&category_id=${catId}&sub_category_id=${subCatId}`, {
method: 'POST',
headers: myHeaders,
})
.then(res => res.json())
.then(data => dispatch({
type: actionType.GET_RELATED_DETAIL,
payload: data
})).catch(error => {
console.log('Got cat Feed', error);
});
}else{
return fetch(`${constants.API}?tag=product_list&category_id=${catId}&sub_category_id=${subCatId}&limit=${limit}&offset=${offset}`, {
method: 'POST',
headers: myHeaders,
})
.then(res => res.json())
.then(data => dispatch({
type: actionType.GET_RELATED_DETAIL,
payload: data
})).catch(error => {
console.log('Got cat Feed', error);
});
}
}
};
Hope it helps.
I guess it's possible that you could do something like this:
return fetch(
"${constants.API}?tag=product_list&category_id=${catId}&sub_category_id=${subCatId}"
+ ((limit!=null) ? "&limit=${limit}" : "")
+ ((offset!=null) ? "&offset=${offset}" : ""), ...

Resources