I'm trying to chain several calls to AsyncStorage.getItem() but cannot seem to get the calls to trigger in the correct order. I seem to manage to drop out of the loop with the last item pleted before earlier items. It appears that React uses a different syntax for promises than how jQuery would work.
In this example I am trying to chain calls to get vars v1, v2, v3. v3 triggers a refresh of the UI for which vars v1 and v2 are required. My code for two chained vars is as follows:
AsyncStorage.getItem("v1")
.then(
(value) => {
if (value !== null){
varCollection.v1 =value
}
}
)
.then( () => {
AsyncStorage.getItem("v3")
.then((value) => {
if (value !== null){
varCollection.v3 = value;
}else{
varCollection.v3 = "default value";
}
})
.done()
})
.done();
This appears to work but it may be simply luck that causing it to work as when I add another link to the chain, things go wrong.
AsyncStorage.getItem("v1")
.then(
(value) => {
if (value !== null){
varCollection.v1 =value
}
}
)
.then( () => {
AsyncStorage.getItem("v2")
.then((value) => {
if (value !== null){
varCollection.v2 = value;
}
})
.done()
})
.then( () => {
AsyncStorage.getItem("v3")
.then((value) => {
if (value !== null){
varCollection.v3 = value;
}else{
varCollection.v3 = "default value";
}
})
.done()
})
.done();
This results in v3 altering and triggering the state of the app to change even though v2 may not have been assigned yet.
Calling console.log() on each of the vars in props.varCollection from getInitialState() of child elements shows v1 is present but v2 isn't or vice versa. I have also tried nesting my calls to create the chain which I realised gets messy quickly.
* Update * Further to SLacks and Bergi's suggestions I have also tried the following:
AsyncStorage.getItem("v1")
.then((value) => {
if (value !== null){
v1 = value;
}
})
.then( () =>{
return(
AsyncStorage.getItem("v2")
.then((value) => {
if (value !== null){
v2 = value;
}
})
)
})
.then( () => {
return(
AsyncStorage.getItem("v3")
.then((value) => {
if (value !== null){
v3 = value;
}
})
)
})
.done();
and
AsyncStorage.getItem("v1")
.then((value) => {
if (value !== null){
v1 = value;
}
})
.then( () =>
(
AsyncStorage.getItem("v2")
.then((value) => {
if (value !== null){
v2 = value;
}
})
)
)
.then( () =>
(
AsyncStorage.getItem("v3")
.then((value) => {
if (value !== null){
v3 = value;
}
})
)
)
.done();
but still get stuck at the second call.
* /Update *
What is the correct way to chain Async calls in React Native?
I'm trying to chain several calls to AsyncStorage.getItem() but cannot seem to get the calls to trigger in the correct order. I seem to manage to drop out of the loop with the last item pleted before earlier items. It appears that React uses a different syntax for promises than how jQuery would work.
In this example I am trying to chain calls to get vars v1, v2, v3. v3 triggers a refresh of the UI for which vars v1 and v2 are required. My code for two chained vars is as follows:
AsyncStorage.getItem("v1")
.then(
(value) => {
if (value !== null){
varCollection.v1 =value
}
}
)
.then( () => {
AsyncStorage.getItem("v3")
.then((value) => {
if (value !== null){
varCollection.v3 = value;
}else{
varCollection.v3 = "default value";
}
})
.done()
})
.done();
This appears to work but it may be simply luck that causing it to work as when I add another link to the chain, things go wrong.
AsyncStorage.getItem("v1")
.then(
(value) => {
if (value !== null){
varCollection.v1 =value
}
}
)
.then( () => {
AsyncStorage.getItem("v2")
.then((value) => {
if (value !== null){
varCollection.v2 = value;
}
})
.done()
})
.then( () => {
AsyncStorage.getItem("v3")
.then((value) => {
if (value !== null){
varCollection.v3 = value;
}else{
varCollection.v3 = "default value";
}
})
.done()
})
.done();
This results in v3 altering and triggering the state of the app to change even though v2 may not have been assigned yet.
Calling console.log() on each of the vars in props.varCollection from getInitialState() of child elements shows v1 is present but v2 isn't or vice versa. I have also tried nesting my calls to create the chain which I realised gets messy quickly.
* Update * Further to SLacks and Bergi's suggestions I have also tried the following:
AsyncStorage.getItem("v1")
.then((value) => {
if (value !== null){
v1 = value;
}
})
.then( () =>{
return(
AsyncStorage.getItem("v2")
.then((value) => {
if (value !== null){
v2 = value;
}
})
)
})
.then( () => {
return(
AsyncStorage.getItem("v3")
.then((value) => {
if (value !== null){
v3 = value;
}
})
)
})
.done();
and
AsyncStorage.getItem("v1")
.then((value) => {
if (value !== null){
v1 = value;
}
})
.then( () =>
(
AsyncStorage.getItem("v2")
.then((value) => {
if (value !== null){
v2 = value;
}
})
)
)
.then( () =>
(
AsyncStorage.getItem("v3")
.then((value) => {
if (value !== null){
v3 = value;
}
})
)
)
.done();
but still get stuck at the second call.
* /Update *
What is the correct way to chain Async calls in React Native?
Share edited May 29, 2015 at 16:07 Moss Palmer asked May 29, 2015 at 15:02 Moss PalmerMoss Palmer 1,8541 gold badge16 silver badges31 bronze badges 2- 1 You need to return the promises to the chain. – SLaks Commented May 29, 2015 at 15:05
- How would I do that? – Moss Palmer Commented May 29, 2015 at 15:05
3 Answers
Reset to default 6I'm not sure why the suggested syntax from Bergi did not work but I found that separating the call and assignment before and after the then statement allowed strict control of ordering and that the return statement should only return the promise from the last call in each block. This may not be the best way to do it, but it seems to work quite well for sequential synchronous reads.
AsyncStorage.getItem("v1")
.then( (value) =>
{
this.setState({v1:value})
return AsyncStorage.getItem("v2")
}
)
.then( (value) =>
{
this.setState({v2: value})
return AsyncStorage.getItem("v3")
}
)
.then( (value) =>
{
this.setState({v3:value})
return AsyncStorage.getItem("v4")
}
)
.then( (value) =>
{
return this.setState({v4:value})
}
).done();
You can see it in action at https://rnplay/plays/51t0cQ
You need to return
those promises from the then
callbacks. Just put a return
statement in front of each, or omit the block braces of your arrow function.
Then you also will only need one single .done()
in the end.
Update: React native supports es7 async await now.
So you can do something like this now,
let x = await <Promisified/async functions>
let y = //use x
and don't forget to wrap then in try,catch ;)