So I have a button. When you click on that button, it takes you to an onSubmit function which looks like this:
onSubmit(e) {
e.preventDefault();
this.props.nextSentence(); //this is async
this.setState({ //this is not yet updating with the right values then
inputField: this.props.activePupil.name
});
}
However: this.props.nextSentence(); is async, so when I set my state immediately after, there are no changes. Right now I have a second button which refers to a second function which just sets the state again. I would like to have this happen automatic though. How could I do this?
async actions are normally either Promises or functions with callbacks.
In case of a Promise you need to use .then like below
this.props.nextSentence().then(() => {
this.setState({...});
})
And in case of a function with callback
this.props.nextSentence(() => {
this.setState({...})
})
However keep in mind than you can get the returned response of your async action and use it to update your state. which is normally the case.
For example
//here response is a json object returned from server
this.props.nextSentence().then((response) => {
this.setState({
data: response.data
});
})
Related
I have built an axios call that returns a Promise which holds a promiseResult with an array.
Now I want to show a popup based on if the array is empty or not.
this is my code:
createPopup = () => {
const { myUser } = this.props;
const { showPopup } = this.state;
MyAxiosCall.fetchGetArray(myUser.id)
.then((data) => {
if (data.length < 1) { this.setState({ showPopup: true }) }
if (data.length > 0) { this.setState({ showPopup: false }) }
});
if (!showPopup) {
return;
}
if (showPopup) {
return <Popup/>
}
}
Right now I am using a bool(ShowPopup that is set to false) to show or hide the popup. My problem is that when I debug the createPopup function it loops the createpopupfunction and always seem to start as false, but it gets the right state the second time it loops thru the function.
How do I get the function to stop looping?
And how can I get the function to wait for the statechange based from the response from my api?
It's been a while since i used react with classes.
in functional components you can simply use useEffect.
in this case setting showPopup as an attribute for <PopUp /> and managing visibility from inside <PopUp /> probably would solve you problem
It’s a lifecycle issue. Convert to a functional component and this should fix your issue.
I think this is happening because your conditions for popup are outside the then() block.
So what's happening is for the first time promise is in pending state and during this your state is unchanged because you are updating the state in then block. As soon as promise gets fullfilled your state changes and you are getting correct state in second go.
Try using async await so that js will wait until your api call is complete and then it will execute the conditions.
I've got an issue where window.open gets called too quickly and my other function doesn't finish and post in time in my onclick function.
I tried setting a timeout on the trackData() but it only worked on occasion and I didn't want to set a longer timeout.
onClick
{() => {
trackData();
window.open("https:google.com", "_self");
})
any ideas?
EDIT: The following works locally but doesn't track when in production. Tracking works EVERYTIME if "_self" is being replaced with "_blank" (which it cannot be)
let postData = async(value) => {
await tracker({
action: value,
})
}
tracker just makes an axios post with the action
<div
className="exampleBTN"
onClick={() => {
postData("example").then(
window.open("https://google.com",
"_self")
)}
}
>
</div>
Locally, I can see the data going into the database.
However, online it doesn't work. It only works if either of these are true:
Doesn't have window.open in the onClick
doesn't have "_self" but "_blank" so it opens in a new tab
I thought my async was wrong so I also tried the following:
onClick={async () => {
await postData("example").then(
window.open("google.com", "_self"))
}}
You can work with .then or async/await to do exactly this when action results in a Promise. Axios requests return Promises.
initiateAsynchronousAction()
.then(result => console.log(result))
Callback inside the .then function will only be executed if the promise is fulfilled by the action executed by the async function.
Minor clarification:
Note that inside the .then() you have to pass a callback function and not just immediately invoke actions you want to perform, even if you don't plan to use the result value. So it will be
.then(result=> console.log('Inside callback!'))
and not
.then(console.log('Inside callback!'))
Async-await is another way to write this, it is simply syntactic sugar, that is just an easier way to write it:
const foo = async () => {
const result = await initiateAsynchronousAction()
console.log(result)
}
The variable result will only be given the value once the Promise is resolved. That is, the assigning of the value will be awaited.
You can chain a .catch in the first case or envelop the task in a try-catch block to catch errors if the Axios promise is unfulfilled.
you can use promise based approache here.use aysnc and await for that.
async function trackData(){
.....
let data = awiat your code
.....
}
function call with promise
trackData().then(res=>{
if(res ==="Success){
window.open("https:google.com", "_self")
}
})
I have the following two functions:
async function queryData(){
const query= await axios.get('...')
const queryStatus = portNames.map(...);
const dataStatus= await Promise.all(queryStatus);
return dataStatus;
}
export function actionData(){
const data = queryData();
return{
type:cst.RECEIVE_DATA,
payload:data
}
}
queryData() function return after some line code some data in promise...in the second function i put the data in payload for sending my action to reducer.
the problem is that when i'm trying to pass my data from first function in two second, if i output my variable in console.log() inside the second function,it shows:
instead if i try to print my variable inside the first function
i'm able to access my value from promise...what could be the problem that might create promise pending in actionData()?..therfore how can i pass my data value from promise to action in a way to dispatch my action with relative data to reducer?
Asynchronous functions always return promises. If you want to get access to the value they contain, you either need to call .then on the promise, or put your code in an async function and await the promise.
Since you are using redux, there are some additional considerations. By default, redux does everything synchronously. Dispatching an action should synchronously go through the reducers and update the state. To do async things with redux you'll need to add a middleware. There are a few possible async middlewares, but the one recommended by the redux team is redux-thunk.
With redux-thunk in your project, instead of dispatching an action object, you can dispatch a function. That function is empowered to do async things and dispatch actions when it's done. So a possible implementation for your case would be something like this:
function actionData() {
return async function(dispatch) {
const data = await queryData();
dispatch({
type: cst.RECEIVE_DATA,
payload: data
});
}
}
Let me explain to you the flow here.
First we come here
const data = queryData();
In queryData function we have:
async function queryData(){
const query= await axios.get('...') <------------ first breakpoint ----------------
// ......
}
When this async req is hit, the code doesn't stop it's flow, it continues. Next return statement is hit.
return {
type:cst.RECEIVE_DATA,
payload:data // data is undefined at this moment
}
In the meantime the async request's response comes back. We sequentially execute the next 3 statements of queryData() function
const queryStatus = portNames.map(...);
const dataStatus= await Promise.all(queryStatus);
return dataStatus;
And now the data variable gets updated.
To ensure proper flow, you could write something like this:
export async function actionData() {
const data = await queryData();
return {
type:cst.RECEIVE_DATA,
payload:data
}
}
I'd encourage to you read about async/await on MDN.
I have two actions on button change function which are dependent on one another. What I want to do is I want to put these two function in async/await structure so that after update_other_filter action ends, that I will be able to run getTotalData action. Running it like below structure actually does not update state in correct way. I am sending previous state(before update_other_filter) in getTotaldata.
You guys will probably say I have to dispatch getTotalData inside update_other_filter action when it resolves. But in this state of my project it seems I can not change anything. I am not really good with async/await and promises concept so, I only want to create async/ await fucntion inside my react component than I want to call it inside onChange function. Is there a way to do that?
onChange = {(event) => {
this.props.setSpinner()
//this update filter function updates filter which will be sent to server in getTotalData action
this.props.update_other_filter(true,"website",!event.target.checked)
//this action should wait for update_other_filter to end than it has correct parameters to send to server
this.props.getTotalData(this.props.totalFilters, apiUrl)
}
async onChange = {(event) => {
this.props.setSpinner()
await this.props.update_other_filter(true,"website",!event.target.checked)
this.props.getTotalData(this.props.totalFilters, apiUrl)
}
// I will make function wait that needs for dependent function and also add some error handling.
async onChange = {(event) => {
this.props.setSpinner()
try
{
await this.props.update_other_filter(true,"website",!event.target.checked)
this.props.getTotalData(this.props.totalFilters, apiUrl)
}
catch(e)
{
thorw e;
}
}
In a component I would like fetch some data from my database using fetch API. When all the data is fetched I would like to change the state of the component using Promise.all():
await Promise.all(data).then(
this.setState({
isLoading: false
})
)
My problem is that setState() fires before the Promises are resolved. However this code works but then isLoading is an array instead of boolean:
this.setState({
isLoading: await Promise.all(data)
})
Does anyone know why? I'm kinda new to React-Native so would love some input!
You should change like this:
await Promise.all(data).then((result) => {
this.setState({
isLoading: false
})
}
)
Basically .then has a function as parameter so you have to put your setState inside an arrow function.
As you are using async/await, you shouldn't call then at all. If you still wanted to use it, you'd need to pass a callback; but your code really should simply look like the following:
await Promise.all(data);
this.setState({
isLoading: false
});
then(
this.setState(...)
)
You're calling setState() immediately and passing its result to then() (just like any other function call).
You need to pass a function or lambda to then() that calls setState.