call a function from within eventListener - reactjs

I want to call a function from within the eventListener
I get this error :
TypeError: this.foo is not a function
I understand that this is the xhr itself and not the class that wraps both function.
How can I call foo from within the eventListener callback?
createStripeUser = async (code) => {
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
this.foo(this.responseText)
}
});
xhr.open("POST", "https://connect.stripe.com/oauth/token");
xhr.send(data);
}
foo = (data ) => {
console.log(data)
}

If you want access this from outside you need to use () => {} instead of function() {} in readyStateChange callback.
createStripeUser = async (code) => {
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", () => {
if (xhr.readyState === 4) {
this.foo(xhr.responseText)
}
});
xhr.open("POST", "https://connect.stripe.com/oauth/token");
xhr.send(data);
foo = (data ) => {
console.log(data)
}
i don't know your code is a class or not. but if it not, just call foo(xhr.responseText) instead.

You must use a alias for this in callback for xhr like this:
const that=this;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
that.foo(this.responseText)
}
});

Related

ExtJS - How can I use async - await functions

I have the following code, using async - await... that works in HTML + JavaScript environment, except if I use it inside EXTJS App, component listener.
...
onListInitialize: function(component, eOpts)
{
const citiesRef= db.collection("cities");
// defining async function
async function getIsCapitalOrCountryIsItaly() {
const isCapital = citiesRef.where('capital', '==', true).get();
const isItalian = citiesRef.where('country', '==', 'Italy').get();
const [capitalQuerySnapshot, italianQuerySnapshot] = await Promise.all([
isCapital,
isItalian
]);
const capitalCitiesArray = capitalQuerySnapshot.docs;
const italianCitiesArray = italianQuerySnapshot.docs;
const citiesArray = capitalCitiesArray.concat(italianCitiesArray);
return citiesArray;
}
//We call the asychronous function
getIsCapitalOrCountryIsItaly().then(result => {
result.forEach(docSnapshot => {
console.log(docSnapshot.data());
});
});
}
...
I'm getting the error: Expected an assigment or function call and instead saw an expression.
I tried Ext.Promise without success.
SOLVED! Using one promise for each query.
Sample of code:
Ext.Promise.all([
new Ext.Promise(function(resolve, reject) {
setTimeout(function() {
resolve('one');
}, 5000);
}),
new Ext.Promise(function(resolve, reject) {
setTimeout(function() {
resolve('two');
}, 4000);
})
])
.then(function(results) {
console.log('first function result', results[0]);
console.log('second function result', results[1]);
Ext.Msg.alert('Success!', 'All promises returned!');
});

Clean up async function in an useEffect React hook

I have the following useEffect function and trying to find the best way to clean this up when the component unmounts.
I thought it would be best to follow the makeCancelable from the React docs, however, the code still executes when the promise is cancelled.
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
val => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
error => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
//example useEffect
useEffect(() => {
const getData = async () => {
const collectionRef_1 = await firestore.collection(...)
const collectionRef_2 = await firestore.collection(...)
if (collectionRef_1.exists) {
//update local state
//this still runs!
}
if (collectionRef_2.exists) {
//update local state
//and do does this!
}
}
const getDataPromise = makeCancelable(new Promise(getData))
getDataPromise.promise.then(() => setDataLoaded(true))
return () => getDataPromise.cancel()
}, [dataLoaded, firestore])
I have also tried const getDataPromise = makeCancelable(getData) without any luck. The code executes fine, just doesn't clean up correctly when the component unmounts.
Do I need to also cancel the two await functions?
In your makeCancelable function you are just checking the value of hasCanceled_ after the promise has finished (meaning getData has already executed entirely):
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
// AFTER PROMISE RESOLVES (see following '.then()'!), check if the
// react element has unmount (meaning the cancel function was called).
// If so, just reject it
promise.then(
val => hasCanceled_ ? reject({isCanceled: true}) : resolve(val),
error => hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
Instead, in this case I would recomend you to go for a simpler and more classic solution and use a isMounted variable to create the logic you want:
useEffect(() => {
let isMounted = true
const getData = async () => {
const collectionRef_1 = await firestore.collection(...)
const collectionRef_2 = await firestore.collection(...)
if (collectionRef_1.exists && isMounted) {
// this should not run if not mounted
}
if (collectionRef_2.exists && isMounted) {
// this should not run if not mounted
}
}
getData().then(() => setDataLoaded(true))
return () => {
isMounted = false
}
}, [dataLoaded, firestore])

ApiFetch pass variable from function JS

I make an api call to an endpoing and inside the apiFetch I get a value. I want to display this value from outside the function but it doesn't get updated. Any ideas why it does this?
save: () => {
var newValue="default";
apiFetch( { path:'/url', } ).then( res => {
newValue = (res[0].value);
// this shows the new value
console.log(newValue);
} );
//this shows "default"
return <p>{newValue}</p>
}
Your function is asynchronous, you can use async/await
save: async () => {
const response = await apiFetch( { path:'/url', } );
const newValue = response[0].value;
console.log(newValue);
return <p>{newValue}</p>
}
Then, inside your caller block:
const newValueParagraph = await yourobject.save();
It looks like you need to return your Promise. Right now you make the async request to the api, and while that's doing it's thing you return newValue which is still just 'default.
Try like this:
save: () => {
var newValue = "default";
return apiFetch({ path: '/url', }).then(res => {
newValue = (res[0].value);
// this shows the new value
console.log(newValue);
return <p>{newValue}</p>
});
}

How can i use promise.all with forEach in asynchronous function

i have a asynchronous function inside that am using forEach and promise.all. my question is how can i make the function stops until one of the value in forEach is rendered completely and then go for the next one.
sentingMailtoOneRestauarnt this is a large function and now am getting only partial values from this because next value in forEach is invoked before the completion of first one.
exports.handler = async () => {
return fetchAllConnectedAcccounts(null).then((response) => {
var promises_array = []
response.forEach((data) => {
if (data) {
var promise = sentingMailtoOneRestauarnt(data, yesterday).then((resp)=>{
promises_array.push(promise);
})
}
})
return Promise.all(promises_array).then((result) => {
return result;
})
}).catch((err) => {
console.log(err)
});
}
From the code, looks like you already are using async here. Skip ove promises -
const responses = await fetchAllConnectedAcccounts(null);
const results = [];
for (const response of responses){
if (response){
results.push(await sentingMailtoOneRestauarnt(response, yesterday));
}
}
// do whatever with results...
Currently your array is full of resolved promises (you push to it only after promise is resolved).
exports.handler = async () => {
return fetchAllConnectedAcccounts(null).then((response) => {
var promises_array = []
response.forEach((data) => {
if (data) {
var promise = sentingMailtoOneRestauarnt(data, yesterday);
promises_array.push(promise); // push to array before promise is resolved
}
})
return Promise.all(promises_array); // wait for resolving here
/*.then((result) => {
return result;
})*/ // unnecessary
}).catch((err) => {
console.log(err)
});

reactJS how to stop it listening to ajax request

I have ajax call in componentdidmount. And and then setState inside the ajax promise.
The code is like this
componentDidMount(){
axios.post('mydomian.com/item/',this.state)
.then(function (response) {
const res = response.data
if (res.status === 'OK') {
this.setState({items :res.list})
}else{
console.log('can not load data', response)
}
}.bind(this))
}
componentWillUnmount(){
how to stop everything about axios?
}
This causes error 'can not setstate on an unmounted component', when I navigate to other route.
So I think what I should do is remove axios listener in the componentwillunmount. How to would you do it?
A very simple solution could be to set a flag on unmount and utilize it within the promise resolution, like so:
componentDidMount(){
axios.post('mydomian.com/item/',this.state)
.then(function (response) {
if (this.unmounted) return;
const res = response.data
if (res.status === 'OK') {
this.setState({items :res.list})
}else{
console.log('can not load data', response)
}
}.bind(this))
}
componentWillUnmount(){
this.unmounted = true;
}
I have find a great solution that has been defined by istarkov
const makeCancelable = (promise) => {
let hasCanceled_ = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then((val) =>
hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
);
promise.catch((error) =>
hasCanceled_ ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel() {
hasCanceled_ = true;
},
};
};
How to use:
const somePromise = new Promise(r => setTimeout(r, 1000));
const cancelable = makeCancelable(somePromise);
cancelable
.promise
.then(() => console.log('resolved'))
.catch(({isCanceled, ...error}) => console.log('isCanceled', isCanceled));
// Cancel promise
cancelable.cancel();
the solution has been found there.
My implementation.
Inside my function
const promiseShareByEmail = makeCancelable(this.props.requestShareByEmail(obj.email, obj.url));
promiseShareByEmail.promise.then(response => {
const res = response.data;
if (res.code != 0)
throw new Error(res.message);
this.setState({
message: {
text: TextMeasurements.en.common.success_share_test,
code: Constants.ALERT_CODE_SUCCESS
}
});
}).catch(err => {
if (err.isCanceled)
return;
this.setState({
message: {
text: err.message,
code: Constants.ALERT_CODE_ERROR
}
})
});
this.promiseShareByEmail = promiseShareByEmail;
this.props.requestShareByEmail(obj.email, obj.url) that function returns promise from axios.
when component will unmount cancel function should be invoked.
componentWillUnmount() {
this.promiseShareByEmail.cancel();
}
enjoy.

Resources