简体   繁体   中英

Firebase Real Time Database read data

I'm building something like a Messenger using React + Redux and Real-Time Database from Firebase.

I'm used to retrieve data from an API like this:

export const fetchContacts = () => {
    return async dispatch => {
        dispatch(fetchContactsStart());

        try {
            const response = await axios.get('....');

            dispatch(fetchContactsSuccess(...));
        } catch(e) {
            dispatch(fetchContactsFail(...));
        }
    }
}

Now in firebase I have the following data: enter image description here

What I need is to get all user contacts and then get user info associated with those contacts and build a structure like: [{email: ..., username: ...}, {email: ..., username: ...}, ...]. After getting all the data in that format I want to dispatch the action to my reducer.

Right now I have the following code:

export const fetchContacts = () => {
    return dispatch => {
        dispatch(fetchContactsStart());

        const userEmail = firebase.auth().currentUser.email;
        let data = [];

        firebase.database().ref(`users_contacts/${Base64.encode(userEmail)}`)
            .on('value', contacts => contacts.forEach(contact => {
                firebase.database().ref(`users/${Base64.encode(contact.val().contact)}`)
                    .on('value', user => {
                        data.push({ email: contact.val().contact, username: user.val().username });
                        console.log(data)
                    })
            }
        ))
    }
}

This works but I don't know how to dispatch the action only when the data is fully formed, is there any solution for this? Thanks for the help!

When you're waiting for multiple asynchronous operations to complete, the solution is usually to use Promise.all . In this case, that'd look something like this:

export const fetchContacts = () => {
  return dispatch => {
    dispatch(fetchContactsStart());

    const userEmail = firebase.auth().currentUser.email;
    let data = [];

    firebase.database().ref(`users_contacts/${Base64.encode(userEmail)}`).once('value', contacts => {
      let promises = [];
      let map = {};
      contacts.forEach(contact => {
        const contactId = Base64.encode(contact.val().contact);
        map[contactId] = contact.val().contact;
        promises.push(firebase.database().ref(`users/${contactId}`).once('value'));
      });
      Promise.all(promises).then((users) => {
        users.forEach((user) =>
          data.push({ email: map[user.key], username: user.val().username });
        })
        // TODO: dispatch the result here
      }
    ))
  }
}

The main changes in here:

  • Now uses once() for loading the user data, so that is only loads once and returns a promise.
  • Uses Promise.all to wait until all profiles are loaded.
  • Added a map to look up the email address in the inner callback.

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