Reputation: 393
I'm using react-native firebase to save my media into firebase. I have a set of URLs that need to be saved in the firebase. For that, I'm using map() to save one by one. After saving I'm pushing the success URL to the array. I need to call a function with this array as a parameter. So I need to call this function after the array is completed. I have searched a lot but I did not find a good explanation for this task. Can anyone help me. Thank you.
var mediaArray = []; //array of success callbacks values
var completedMediaSurveysAnswers = [{}, {}, {}]; //object array of URLs and media types
completedMediaSurveysAnswers.map((i) => {
try {
const storage = firebase.storage();
const mRef = storage.ref('portal').child('Survey/Image/user/' + uuidv4() + 'media');
mRef.putFile(i.urlPath, {
contentType: i.mediaType
})
.on('state_changed', snapshot => {},
err => {
console.log('Failed to upload file to firebase storage')
},
uploadedFile => {
// Success
this.setState({
mediaPath: uploadedFile.downloadURL
})
mediaArray.push(this.state.mediaPath)
});
} catch (error) {
console.log(error)
}
})
//need to call this function after loop is done
saveAnswers(mediaArray)
Upvotes: 5
Views: 5743
Reputation: 1217
As per my knowledge we can dom something like below.
Learn From : https://www.codegrepper.com/code-examples/javascript/wait+for+map+to+finish+javascript
Perform an action after .map() completion:
var promises = testUserArray.map((item, index) => {
console.log('item', item)
})
await Promise.all(promises).then(() => {
console.log('Map Opration Successfully Completed')
})
Example App:
import React, { useState } from 'react'
import { View, StatusBar, Text, Button } from 'react-native'
export default function App() {
const [testUserArray, setTestUserArray] = useState(testArray)
const _testMap = async () => {
var promises = testUserArray.map((item, index) => {
console.log('item', item)
})
await Promise.all(promises).then(() => {
console.log('Map Opration Successfully Completed')
})
}
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', }}>
<Button
title='Test .map()'
onPress={() => _testMap()}
/>
</View>
)
}
const testArray = [
{
"id": '1',
"name": 'User 1'
},
{
"id": '2',
"name": 'User 2'
},
{
"id": '3',
"name": 'User 3'
},
{
"id": '4',
"name": 'User 4'
},
{
"id": '5',
"name": 'User 5'
},
]
Upvotes: 1
Reputation: 792
You can use Promise or async/await to handle all kind of these situations like this:
var mediaArray = [];
var completedMediaSurveysAnswers = [{}, {}, {}];
async function handleYourTask() {
await completedMediaSurveysAnswers.map((i) => {
try {
const storage = firebase.storage();
const mRef = storage.ref('portal').child('Survey/Image/user/' + uuidv4() + 'media');
mRef.putFile(i.urlPath, {
contentType: i.mediaType
})
.on('state_changed', snapshot => {},
err => {
console.log('Failed to upload file to firebase storage')
},
uploadedFile => {
// Success
this.setState({
mediaPath: uploadedFile.downloadURL
})
mediaArray.push(this.state.mediaPath)
});
} catch (error) {
console.log(error)
}
})
await saveAnswers(mediaArray);
}
and then you can call handleYourTask function anywhere you want :)
Upvotes: 3
Reputation: 713
Just check the length of your map array and compare it with map key.
Use async await
to wait till file to upload
var mediaArray = []; //array of success callbacks values
var completedMediaSurveysAnswers = [{}, {}, {}]; //object array of URLs and media types
completedMediaSurveysAnswers.map(async (i, key) => {
try {
const storage = firebase.storage();
const mRef = storage.ref('portal').child('Survey/Image/user/' + uuidv4() + 'media');
await mRef.putFile(i.urlPath, {
contentType: i.mediaType
})
.on('state_changed', snapshot => {},
err => {
console.log('Failed to upload file to firebase storage')
},
uploadedFile => {
// Success
this.setState({
mediaPath: uploadedFile.downloadURL
})
mediaArray.push(this.state.mediaPath)
});
if( key == (completedMediaSurveysAnswers.length - 1 ) ){
saveAnswers(mediaArray)
}
} catch (error) {
console.log(error)
}
})
I don't tested async await
so use it wherever its set.
Upvotes: 0
Reputation: 6264
using .map is good, so you can return an Array of promises which you can then wait for their resolution
in this case, the resolved value in Promise.all will be what you were pushing into an array ... i.e. this.state.mediaPath
var completedMediaSurveysAnswers = [{}, {}, {}]; //object array of URLs and media types
var promises = completedMediaSurveysAnswers.map((i) => new Promise((resolve, reject) => {
try {
const storage = firebase.storage();
const mRef = storage.ref('portal').child('Survey/Image/user/' + uuidv4() + 'media');
mRef.putFile(i.urlPath, {
contentType: i.mediaType
}).on('state_changed', snapshot => {}, err => {
console.log('Failed to upload file to firebase storage');
resolve(null); // so one failure doesn't stop the whole process
}, uploadedFile => {
// Success
this.setState({
mediaPath: uploadedFile.downloadURL
})
resolve(this.state.mediaPath)
});
} catch (error) {
console.log(error)
resolve(null); // so one failure doesn't stop the whole process
}
}));
//need to call this function after loop is done
Promise.all(promises).then(mediaArray => {
saveAnswers(mediaArray);
});
Upvotes: 1