简体   繁体   中英

How to retrieve an ID array and then use that to retrieve documents from Firestore in React Native?

I am fairly new to both Firebase and React Native . In the Firestore , I have set up a "users" collection where each user document has an array of IDs representing events he has selected. 图像

These IDs correspond to the name of the event documents in the "events" collection. 图像

In React Native , I am trying to retrieve the selectedEvents array from the user before using this IDs array to retrieve the actual events and render them in a FlatList. The FlatList uses a state called "events" as data. Here is my code:

 function SelectedScreen(props) { // The events array to be displayed in the FlatList const [events, setEvents] = useState([]); const { user } = useContext(AuthContext); const userRef = firebase.firestore().collection("users").doc(user.id); const eventsRef = firebase.firestore().collection("events"); function onRefresh() { // An empty array to push events into const newSelected = []; userRef .get() .then((userDoc) => { // The retrieved ID array const selectedIds = userDoc.data().selectedEvents; // For each ID in the array, get the corresponding // event document from the "events" collection // and push it into the newSelected array selectedIds.forEach((eventId) => { eventsRef .doc(eventId) .get() .then((eventDoc) => { const event = eventDoc.data(); newSelected.push(event); }) .catch((error) => alert(error)); }); }) .catch((error) => alert(error)); // Set the events to be the newSelected array setEvents(newSelected); } return ( // A simple button to retrieve the events when pressed <Button title="Refresh" onPress={onRefresh} /> // A button to log the events to the console for testing <Button title="Test" onPress={() => console.log(events)} /> // The FlatList to show the events <FlatList data={events} keyExtractor={(event) => event.id.toString()} ItemSeparatorComponent={ListItemSeparator} renderItem={({ item }) => ( // A custom component to display each event <SelectedItem title={item.title} dateTime={item.dateTime} id={item.id} /> )} /> ); }

When I press the "Refresh" button, nothing shows on the screen (the FlatList displays nothing). However, when I press the "Test" button after that to log "events" to the console, it shows the retrieved events array as intended.

The problem probably lies with the "events" state, but I don't know how to fix it. Any recommendation for change in both the backend and the frontend will be appreciated too. Thank you.

The problem is that you are not appropiately rendernig the list, as your are missing the function to render the elements, that would be something like this:

const renderItem = ({item}) => {
  return <View><Text>{item.name}</Text></View>
}

Have a look at this article for detailed information.

I've managed to solve the issue by using map instead of forEach to match each event ID to that event, as well as making the function async and awaiting each command. Here's my new code:

 function onRefresh() { const newSelected = []; userRef .get() .then(async (userDoc) => { const selectedIds = await userDoc.data().selectedEvents; if (selectedIds !== []) { await Promise.all( selectedIds.map(async (eventId) => { await eventsRef .doc(eventId) .get() .then(async (eventDoc) => { const event = await eventDoc.data(); newSelected.push(event); }) .catch((error) => alert(error)); }) ); setEvents(newSelected); } }) .catch((error) => alert(error)); }

The events are displayed as intended now, and I am left perplexed as to what exactly went wrong before. Oh well, as long as it works I suppose.

You can run all the Promises simultaneously using Promise.all()

function onRefresh() {
    // An empty array to push events into
    const newSelected = [];
    return userRef
        .get()
        .then(async (userDoc) => {
            // The retrieved ID array
            const selectedIds = userDoc.data().selectedEvents;
            // For each ID in the array, get the corresponding
            // event document from the "events" collection
            // and push it into the newSelected array
            const eventsSnapshot = await Promise.all(selectedIds.map((eventId) => eventsRef.doc(eventId).get()))
            const events = eventsSnapshot.map(evt => evt.data())
            newSelected = [...newSelected, ...events];
        }).catch((error) => alert(error));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM