How to synchronize fetch method in redux action - reactjs

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.

Related

REDUX - how to store ARRAY id's when i do a dispatch loop?

I need to save the ID's that I am receiving when fetching in a loop in the store but I am not realizing how to iterate the object
This is my action's
export function uploadImage(files) {
return function async(dispatch) {
const myHeaders = new Headers();
myHeaders.append("Authorization", `Token ${localStorage.getItem('***')}`)
for(let i = 0; i < files.length; i++) {
const formdata = new FormData();
formdata?.append("image", files[i], files[i].name);
fetch(`${process.env.REACT_APP_URL_API}/api/images/`, {
'method': "POST",
'headers': myHeaders,
'body': formdata,
'redirect': 'follow'
})
.then(resp => resp.json())
.then(json => dispatch(activeImage(json.id)))
}
}
}
export const activeImage = ( id ) => ({
type: "PUSH_ID_IMAGE",
payload: id
});
My reducer:
case "PUSH_ID_IMAGE":
return{
...state,
images: [...action.payload]
}
Redux actions don't support async actions by defualt, you could try using redux-thunk
It allows you to return a function as an action and gives you access to dispatch and getState so you can dispatch events to your reducer from within the function as well as being able to retrieve the state
After installing redux-thunk you could write something like this as your action:
const uploadImage = files => {
return async (dispatch, getState) => {
// ... your proccessing / loop here
// ... inside the loop
const response = await fetch(`${process.env.REACT_APP_URL_API}/api/images/`, {
'method': "POST",
'headers': myHeaders,
'body': formdata,
'redirect': 'follow'
})
.then(resp => resp.json())
dispatch({
type: "PUSH_ID_IMAGE",
payload: response
}) // send the data returned from "resp.json"
}
}

Make Redux thunk calls synchronous for refreshing tokens

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
};
}

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())
}));
}```

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 make this into a function

I have this redux hook. I will essentially be creating fetchStudents for student, district, school, etc. Instead of rewriting this code, I essentially want to be able to pass in the URL and the type. How can I do this?
import fetch from 'isomorphic-fetch';
import { createAction } from 'utils/actionUtils';
import * as types from './StudentConstants';
export const setLoading = createAction(types.SET_LOADING);
const getStudents = students => ({
type: types.SET_STUDENTS,
payload: students,
});
export const fetchStudents = (students) => {
return (dispatch) => {
return fetch('http://gsndev.com/gsndb/student/', {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `JWT ${localStorage.token}`,
},
})
.then(response => response.json())
.then((s) => {
dispatch(getStudents(s));
})
.catch(error => (error));
};
};
fetchStudents is normal function. So pass any arguments you want and use these arguments for branching logic.
For example
export const fetchStudents = (type, url) => {
return (dispatch) => {
return fetch(url, { // Here you may put url
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: `JWT ${localStorage.token}`,
},
})
.then(response => response.json())
.then((s) => {
switch (type) {
case 'students':
dispatch(getStudents(s));
break;
case 'district':
dispatch(getDistricts(s)); // There can be action creator for districts
break;
// And so on for other types
}
})
.catch(error => (error));
};
};

Resources