web-dev-qa-db-fra.com

manière correcte d’utiliser Firestore onSnapShot avec Reaction redux

J'essaie de trouver la bonne façon d'utiliser firestore.onSnapshot avec react-redux.

J'ai actuellement ce code dans mon fichier d'action, que j'appelle sur componentWillMount() dans mon composant.

export const fetchCheckins = () => async (dispatch) => {
const {currentUser} = firebaseService.auth();
try {
    let timestamp = (new Date());

    //set timestamp for beginning of today
    timestamp.setHours(0);
    //get checkins today
    let checkinstoday = (await firebaseService.firestore().collection(`/checkins/${currentUser.uid}/log`).where("timestamp",">=",timestamp).orderBy("timestamp","desc").get()).docs.map(doc => doc.data());
    //set timestamp for beggining of week
    timestamp.setDate(-(timestamp.getDay()));
    //get checkins (week)
    let checkinsweek = (await firebaseService.firestore().collection(`/checkins/${currentUser.uid}/log`).where("timestamp",">=",timestamp).orderBy("timestamp","desc").get()).docs.map(doc => doc.data());
    //set timestamp for begging of month
    timestamp.setDate(0);
    //get checkins (month)
    let checkinsmonth = (await firebaseService.firestore().collection(`/checkins/${currentUser.uid}/log`).where("timestamp",">=",timestamp).orderBy("timestamp","desc").get()).docs.map(doc => doc.data()); 

    dispatch({type: FETCH_CHECKINS, payload: { today: checkinstoday, week: checkinsweek, month: checkinsmonth}});
}
catch(e){
  console.error(e);
}

};

cela fonctionne correctement, les données correctes sont envoyées au composant et affichées. Le problème est que si l'utilisateur se connecte, les données d'archivage doivent s'ajuster, mais ce n'est pas le cas, car je reçois les données une fois et je les envoie, et l'état n'est pas en cours de restitution.

Ma question est comment je devrais aborder ceci? Est-ce que j'utilise .onSnapshot() au lieu de .get()? Est-ce que j'appelle .fetchCheckins() à partir du créateur de l'action .checkin()? Comment puis-je aborder selon les meilleures pratiques? Je vous remercie

2
Jakob

Selon la documentation de firestore, si vous avez besoin de mises à jour en temps réel, utilisez onSnapshot: https://firebase.google.com/docs/firestore/query-data/listen

Dans votre cas, si vous utilisez .get (), vous obtenez la mise à jour une seule fois et Firestore ne vous avertira pas si l'une des données change. C'est pourquoi vous ne voyez pas les changements.

P.S. checkout redux-firestore: https://github.com/prescottprue/redux-firestore - c’est une jolie bibliothèque qui peut vous aider avec vos liaisons redux.

3
Daniel Dimitrov

Vous pouvez inscrire votre liste comme ceci:

function subscribeToExperiences() {
  return eventChannel((emmiter: any) => {
    experiencesRef.onSnapshot({ includeMetadataChanges: true }, snapshot => {
      const experiences: IExperience[] = snapshot.docChanges().map(change => ({
        id: change.doc.id,
        title: change.doc.data().title
      }));

      if (snapshot.docChanges().length !== 0) {
        emmiter(experiences);
      }
    });

    return () => experiencesRef;
  });
}

function* fetchExperiences(_: ExperiencesFetchRequested) {
  const channel = yield call(subscribeToExperiences);
  try {
    while (true) {
      const experiences = yield take(channel);
      yield put(new ExperiencesFetchSucceeded(experiences));
    }
  } finally {
    if (yield cancelled()) {
      channel.close();
    }
  }
}

subscribeToExperiences utilise un redux-sagaeventChannel. Un eventChannel reçoit un emmiter qui génère un effet de saga à consommer avec take. La eventChannel doit renvoyer une fonction pour fermer les connexions, mais autant que les connexions .onSnapshot ne soient pas explicitement fermées, c'est pourquoi je retourne une fonction fictive.

1
Mario Gil