Promise.all() and setState() react-native - javascript

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.

Related

passing data with async/await in action function

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.

Using promises in react-redux actions dispatch functions?

I am new to react-redux . I want to know is this ok to use ES6 promises with actions dispatch functions ? Suppose i want to show success toast after request success . What i did is resolve promise when request hit successfully.See example code below
#Example
function login(credentials){
return dispatch => {
return new Promise((resolve,reject)=> {
dispatch(login_request);
service.login(credentials)
.then(
(data)=> {
dispatch(login_success,data);
resolve();
})
}) }}
Then calling that function from UI what i did,
login().then(success => show_toast());
Is this approach OK to show toast?
Technically it's fine, though personally i think its unnecessary to chain to this promise.
You already dispatching an action inside your thunk login_success, so you can use this as a condition to show the toast

React setState with function

I am attempting to setState in a React component using a function callback which is now the recommended way.
It is in the componentDidMount and when I get my jobs data back I need to update the state.
It works when I set it directly but I have attempted may functions callbacks and cannot get it to work.
Sample code provided below with one of my many attempts.
async componentDidMount(){
const jobs = await loadJobs();
this.setState({jobs});
//this.setState((prevState, jobs) => {return {jobs: [prevState,...jobs]}})
}
What is the correct syntax?
You only need to make use of functional setState when you want to update current state based on prevState, in your case it seems like you just want to set the state jobs, you would simply write
this.setState({jobs});
However if you want to use functional setState, you would still write
this.setState((prevState) => {
return {jobs};
})
You need to update the jobs by getting value from prevState and appending the result to the previous state, you would do it like
async componentDidMount(){
const jobs = await loadJobs();
this.setState((prevState) => {
return {jobs: [...prevState.jobs, ...jobs]}
})
}

Function not loading inside componentDidMount ()

I have the following code:
componentDidMount () {
fetch('/data')
.then(res => res.json())
.then(data => this.setState({data}));
this.countVar();
}
countVar () {
//iterate through this.state.data and filter out certain values
}
The countVar() function isn't loading inside componentDidMount(). When I did console.log(this.state.data) right after the componentDidMount()-function, it returned an empty array, so I guess that's the reason.
I tried to use componentDidUpdate() instead if countVar(), but I didn't consider that that would create an infinite loop. I don't quite know how to handle this.
The data that I'm fetching consists of several object arrays. in countVar() I'm filtering out a certain object array, hence the structure of my functions.
Does anyone know how I could solve this problem?
fetch('/data')
.then(res => res.json())
.then(data => this.setState({data}));
This code is async. This means that when the fetch is complete, it will run the functions passed into the then callback. You're running your iteration function directly after registering the promise; not after the promise is resolved.
ALSO
this.setState is not synchronous. You can't guarantee that after you request that the state is set, it is set. It is set some time afterward, but React provides an option for this; you pass in a callback function once state setting is complete.
this.setState({ data }, () => console.log('do something'))
You should call this.countVar inside the then of the Promise otherwise it will run before the fetch Promise is over.
Like this:
componentDidMount () {
fetch('/data')
.then(res => res.json())
.then(data => {
this.setState({data}, this.countVar);
});
}
I'm running this.countVar as a callback to setState so that it runs once setState is done.

React - Setting state immediately after an async action

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

Categories