Cancelling Axios get request in React - reactjs

I have an Axios get request I'd like to cancel upon an event but it doesn't seem to work.
// user.services.js
searchFAQS(query) {
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
source.cancel('Operation cancelled by user')
return axios.get(
authHeader.getApiUrl() + '/api/v1/search_faqs',
{
cancelToken: source.token,
params: {
query: query
}
}
)
}
// ClassComponent
onChangeQuery = (e) => {
if (e.target.value === "") {
this.setState({
fFaq: "",
query: e.target.value
})
} else {
UserServices.searchFAQS().cancel()
this.setState({query: e.target.value},
() => UserServices.searchFAQS(this.state.query)
.then(resp => {
this.setState({
fFaq: resp.data,
fGroups: resp.data.map(f => f.group).filter((value, index, self) => self.indexOf(value) === index)
})
}))
}
}
I read the cancellation part for the Axios documentation, which is what led me to the attempt above, but it doesn't seem to be canceling after observing the requests from developer tools.

searchFAQS(query) {
const CancelToken = axios.CancelToken;
.....
new CancelToken is creating on every searchFAQS call, so it will not get cancel because everytime it's a new token
change as below
let token = null; // define cancel token outside the search fn, then it will not recreate on every call
searchFAQS(query) {
if (token !== null) {
token();
}
...
const { CancelToken } = axios;
...
return axios.get(
authHeader.getApiUrl() + '/api/v1/search_faqs',
{
cancelToken: new CancelToken(function executor(cancellableFn) {
token = cancellableFn;
}),
params: {
query: query
}
}
....

On my understanding you solution should looks like this:
// user.services.js
async searchFAQS(query, source = '') {
const search = axios.get(
authHeader.getApiUrl() + '/api/v1/search_faqs',
{
cancelToken: source.token,
params: {
query: query
}
}
);
if (source /* change to your needs, actualy it cancels all requests */) {
source.cancel('Ok, its just canceled!');
}
return await search.data;
}
// ClassComponent
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
onChangeQuery = (e) => {
if (e.target.value === "") {
this.setState({
fFaq: "",
query: e.target.value
})
} else {
UserServices.searchFAQS("", source)
this.setState({query: e.target.value},
() => UserServices.searchFAQS(this.state.query, source)
.then(resp => {
this.setState({
fFaq: resp.data,
fGroups: resp.data.map(f => f.group).filter((value, index, self) => self.indexOf(value) === index)
})
}))
}
}

Related

How to make a PATCH request in ReactJS ? (with Nestjs)

nestjs controller.ts
#Patch(':id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
#Body('shippingAddr') addrShipping: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling, addrShipping);
return null;
}
nestjs service.ts
async updateProduct(
addressId: string,
addrBilling: boolean,
addrShipping: boolean,
) {
const updatedProduct = await this.findAddress(addressId);
if (addrBilling) {
updatedProduct.billingAddr = addrBilling;
}
if (addrShipping) {
updatedProduct.shippingAddr = addrShipping;
}
updatedProduct.save();
}
there is no problem here. I can patch in localhost:8000/address/addressid in postman and change billingAddr to true or false.the backend is working properly.
how can i call react with axios?
page.js
const ChangeBillingAddress = async (param,param2) => {
try {
await authService.setBilling(param,param2).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
return....
<Button size='sm' variant={data.billingAddr === true ? ("outline-secondary") : ("info")} onClick={() => ChangeBillingAddress (data._id,data.billingAddr)}>
auth.service.js
const setBilling = async (param,param2) => {
let adressid = `${param}`;
const url = `http://localhost:8001/address/`+ adressid ;
return axios.patch(url,param, param2).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}
I have to make sure the parameters are the billlingddress field and change it to true.
I can't make any changes when react button click
Since patch method is working fine in postman, and server is also working fine, here's a tip for frontend debugging
Hard code url id and replace param with hard coded values too:
const setBilling = async (param,param2) => {
// let adressid = `${param}`;
const url = `http://localhost:8001/address/123`; // hard code a addressid
return axios.patch(url,param, param2).then((response) => { // hard code params too
console.log(response); // see console result
if (response.data.token) {
// localStorage.setItem("user", JSON.stringify(response.data));
}
// return response.data;
})
}
now it worked correctly
#Patch('/:id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling);
return null;
}
const ChangeBillingAddress = async (param) => {
try {
await authService.setBilling(param,true).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
const setBilling= async (param,param2) => {
let id = `${param}`;
const url = `http://localhost:8001/address/`+ id;
return axios.patch(url,{billingAddr: param2}).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}

Wait for get request response before continuing with a post request in axios

I have tried to use async/await in the createSwap function but it did not work for me. Before creating a request, I want to run the getSlotDetails function to set the slotDets so that it can be used in the post request below. However, the createSwap function does not wait for the getSlotDetails function to complete before sending the post request. How do I fix this?
const [slotDets, setSlotDets] = useState([]);
const getSlotDetails = (moduleCode, slotId, slotType) => {
axios
.get(`https://api.nusmods.com/v2/2020-2021/modules/${moduleCode}.json`)
.then((response) => response.data)
.then((data) => data.semesterData[0])
.then((semesterData) => semesterData.timetable)
.then((timetable) =>
timetable.filter(
(slot) => slot.classNo === slotId && slot.lessonType == slotType
)
)
.then((result) => {
setSlotDets(result);
});
};
const createSwap = (
moduleCode,
slotType,
currentSlot,
desiredSlots,
completed,
reserved
) => {
dispatch(createRequest());
getSlotDetails(moduleCode, currentSlot, slotType);
axios
.post(
"http://localhost:3001/api/v1/swaps",
{
module_code: moduleCode,
slot_type: slotType,
current_slot: currentSlot,
desired_slots: desiredSlots,
completed: completed,
reserved: reserved,
venue: slotDets.venue,
startTime: slotDets.startTime,
endTime: slotDets.endTime,
day: slotDets.day,
},
{
headers,
}
)
.then((response) => {
console.log(response.data);
dispatch(createSuccess());
setTimeout(() => {
dispatch(resetSwap());
}, 2000);
})
.catch((error) => {
console.log(error.response.data);
dispatch(createFail(error.response.data));
setTimeout(() => {
dispatch(resetSwap());
}, 2000);
});
};
const makeTwoRequests = async () => {
try{
const firstResponse = await axios.get(FIRST_URL);
if(firstResponse.status === 200){
const firstResponseData = firstResponse.data;
const secondResponse = await axios.get(SECOND_URL);
if(secondResponse.status === 200){
const secondResponseData = secondResponse.data;
}
}
}
catch(error){
console.log(error)
}
}
maketwoRequests()
firstResponseData and secondResponseData can be state variables instead of const for better access throughout the Component

React native - React Hook useEffect has a missing dependency:'getAllPost'. Either include it or remove the dependency array.",

I am new in react native and try to call two api from useEffect but it give me this error every time React Hook useEffect has a missing dependency: 'getAllPost'. Either include it or remove the dependency array.
Here is my code
export default function Home({navigation}) {
const [arrCat, setArrCat] = useState([]);
const [arrPost, setArrPost] = useState([]);
const [isLoading, setLoding] = useState(false);
function getAllCategory() {
setLoding(true);
let apiResponse = ApiManager.GET('category/all', [], 'GET');
apiResponse
.then(response => {
let responseJson = response[1];
let status = response[0];
setLoding(false);
let message =
responseJson.message != null
? response.message
: 'Something went wrong';
if (status === 200) {
setArrCat([...responseJson.data]);
getAllPost();
}
setTimeout(function() {
if (message != null) {
Toast.showWithGravity(message, Toast.LONG, Toast.BOTTOM);
}
}, 120);
})
.catch(error => {
console.error(error);
Toast.showWithGravity(error, Toast.LONG, Toast.BOTTOM);
setTimeout(function() {
setLoding(false);
}, 60);
});
}
function getAllPost() {
GetLocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 15000,
})
.then(location => {
console.log(location);
const dictData = {
lat: '-37.81400200-33.865143', //location.latitude,
lang: '144.9546943', //location.longitude,
record_count: '0',
};
console.log(dictData);
let apiResponse = ApiManager.POST(
'post/getRecommendedPost',
dictData,
'POST',
);
apiResponse
.then(response => {
let responseJson = response[1];
let status = response[0];
if (status === 200) {
console.log(responseJson);
setArrPost(oldValue => [...oldValue, ...responseJson.data]);
console.log(arrPost);
} else {
// console.error(responseJson);
Toast.showWithGravity(
responseJson.message,
Toast.LONG,
Toast.BOTTOM,
);
}
})
.catch(error => {
// console.error(error);
Toast.showWithGravity(error.message, Toast.LONG, Toast.BOTTOM);
// setTimeout(function() {
// setLoding(false);
// }, 60);
});
})
.catch(error => {
// const {code, message} = error;
// console.warn(code, message);
Toast.showWithGravity(error.message, Toast.LONG, Toast.BOTTOM);
});
}
useEffect(() => {
console.log('Home screen mounted');
getAllCategory();
// getAllPost();
}, []);
return ( ....)
}

How to make Async Await Function in React Native?

I want to create a function that is about uploading photo to Firebase Storage with react-native-fetch-blob. I'm using Redux and you can find action functions below:
My problem is that uploadImage function is not running like asynchronous. Firebase function is running before uploadImage, so application give me an error.
I think i can't make a asynchronous function. How can i fix it ?
uploadImage() function:
const uploadImage = async (imageSource, whereToUpload) => {
let imageURL = '';
const mime = 'image/jpg';
const { Blob } = RNFetchBlob.polyfill;
const { fs } = RNFetchBlob;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
console.log('URI =>', imageSource.uri);
let imgUri = imageSource.uri;
let uploadBlob = null;
const imageRef = firebase.storage().ref(whereToUpload + '/' + imageSource.fileName);
const uploadUri = Platform.OS === 'ios' ? imgUri.replace('file://', '') : imgUri;
await fs.readFile(uploadUri, 'base64')
.then((data) => Blob.build(data, { type: `${mime};BASE64` }))
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
// eslint-disable-next-line no-return-assign
return imageURL = imageRef.getDownloadURL();
})
.catch((error) => {
console.log(error);
});
return imageURL;
};
and the main action is:
export const addProjectGroup = (
myUser,
groupName,
groupDescription,
groupProfilePic,
) => dispatch => {
const groupProfileFinalPic = async () => {
let finalGroupPicture = { landscape: '' };
if (_.isEmpty(groupProfilePic.src)) {
await uploadImage(groupProfilePic, 'groupPictures').then((imageURL) => {
console.log('İŞLEM TAMAM!');
console.log('SELECTED IMAGE URL =>', imageURL);
finalGroupPicture.landscape = imageURL;
});
} else {
finalGroupPicture.landscape = groupProfilePic.src.landscape;
}
return finalGroupPicture;
};
console.log("final group profile pic =>", groupProfileFinalPic());
// Önce grubu yaratalım..
// eslint-disable-next-line prefer-destructuring
const key = firebase
.database()
.ref()
.child('groups')
.push().key;
firebase
.database()
.ref('/groups/' + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid,
},
groupName,
groupDescription,
groupProfilePic: groupProfileFinalPic(),
projects: '',
})
.then(() => {
console.log('Groups oluşturuldu.');
})
.catch(e => {
Alert.alert('Hata', 'Beklenmedik bir hata meydana geldi.');
console.log(e.message);
});
dispatch({
type: ADD_PROJECT_GROUP,
});
};
You are not awaiting groupProfileFinalPic(). This should be done before creating the action you want to dispatch.
groupProfileFinalPic().then(groupProfilePic => {
return firebase
.database()
.ref("/groups/" + key)
.set({
admin: {
email: myUser.email,
name: myUser.name,
uid: myUser.uid
},
groupName,
groupDescription,
groupProfilePic,
projects: ""
})
.then(() => {
console.log("Groups oluşturuldu.");
})
.catch(e => {
Alert.alert("Hata", "Beklenmedik bir hata meydana geldi.");
console.log(e.message);
});
});
I have no clue what the last dispatch is for, you might want to do that in one of the callbacks. Your code is to verbose for an SO question, but I hope this helps anyways.
You are using both await and then on the same call. To use await, you can arrange it something like
const uploadImage = async (imageSource, whereToUpload) => {
...
try {
let data = await RNFS.fs.readFile(uploadUri, 'base64')
let uploadBlob = await Blob.build(data, { type: `${mime};BASE64` }))
...etc...
return finalResult
catch (e) {
// handle error
}
}

Dispatching action from onUploadProgress event using Redux-Thunk / Axios

The following code uploads a file no problem and responds successfully or failing as expected, however, I cannot figure out how to dispatch my uploadFileProgress action from the onUploadProgress event. I can console.log the progress / percentage and when I try to wrap the dispatch in an IIFE, I trigger a dispatch is not a function error. Hopefully this is a small issue I'm missing. Thanks in advance!
export function uploadFile(values, callback = () => {}) {
const uploadFileData = new FormData();
uploadFileData.append('fileName', values.fileName);
uploadFileData.append('file', values.file);
uploadFileData.append('file', {
filename: values.filename,
contentType: values.contentType,
});
const uploadProgress = {
onUploadProgress: (ProgressEvent) => {
let progressData = 0;
const totalLength = ProgressEvent.lengthComputable ? ProgressEvent.total : ProgressEvent.target.getResponseHeader('content-length') || ProgressEvent.target.getResponseHeader('x-decompressed-content-length');
if (totalLength !== null) {
progressData = Math.round((ProgressEvent.loaded * 100) / totalLength);
}
return function action(dispatch) {
dispatch(uploadFileUpload(progressData));
};
},
};
const configPlusProgress = Object.assign(uploadProgress, config);
const request = () => axios.post(myURL, uploadFileData, configPlusProgress);
return function action(dispatch) {
dispatch(uploadFileLoading(true));
return request()
.then((response) => {
if (response.status !== 201) {
dispatch(uploadFileFail());
throw Error(response.statusText);
}
dispatch(uploadFileLoading(false));
return response;
})
.then(response => dispatch(uploadFileSuccess(response)))
.then(() => callback())
.catch(err => dispatch(uploadFileFail(err)));
};
}
move your request config inside returned function (where dispatch function will be accessible):
export function uploadFile(values, callback = () => {}) {
const uploadFileData = new FormData();
uploadFileData.append('fileName', values.fileName);
uploadFileData.append('file', values.file);
uploadFileData.append('file', {
filename: values.filename,
contentType: values.contentType,
});
return function action(dispatch) {
const uploadProgress = {
onUploadProgress: (ProgressEvent) => {
let progressData = 0;
const totalLength = ProgressEvent.lengthComputable ? ProgressEvent.total : ProgressEvent.target.getResponseHeader('content-length') || ProgressEvent.target.getResponseHeader('x-decompressed-content-length');
if (totalLength !== null) {
progressData = Math.round((ProgressEvent.loaded * 100) / totalLength);
}
dispatch(uploadFileUpload(progressData));
},
};
const configPlusProgress = Object.assign(uploadProgress, config);
const request = () => axios.post(myURL, uploadFileData, configPlusProgress);
dispatch(uploadFileLoading(true));
return request()
.then((response) => {
if (response.status !== 201) {
dispatch(uploadFileFail());
throw Error(response.statusText);
}
dispatch(uploadFileLoading(false));
return response;
})
.then(response => dispatch(uploadFileSuccess(response)))
.then(() => callback())
.catch(err => dispatch(uploadFileFail(err)));
};
}
Also onUploadProgress should just dipatch upload progress event.
I can't quite fix your code but here is a basic function with redux-thunk doing async stuff and using actions.
const doSomeAsyncStuff = () =>
async ( dispatch ) => {
try {
const response = await someAsyncStuff();
return dispatch( someSuccessAction( response.data );
} catch ( error ) {
return dispatch( someFailureAction( err );
}
}
Of course redux-thunk must be added as a middleware.
why are you returning a function from onUploadProgress function
return function action(dispatch) {
dispatch(uploadFileUpload(progressData));
};
Instead of that you can just
dispatch(uploadFileUpload(progressData));

Resources