将 firestore onSnapShot 与 react redux 一起使用的正确方法
correct way to use firestore onSnapShot with react redux
我正在尝试找出将 firestore.onSnapshot 与 react-redux 一起使用的正确方法。
我目前在我的操作文件中有这段代码,我在我的组件中调用 componentWillMount()
。
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);
}
};
这工作正常,正确的数据被发送到组件并显示。问题是,如果用户签入,签入数据应该调整,但它没有,因为我只获取一次数据并发送它,并且状态没有重新呈现。
我的问题是我应该如何处理这个问题?我是否使用 .onSnapshot()
而不是 .get()
?我是从 .checkin()
动作创建者那里调用 .fetchCheckins()
吗?我如何根据最佳实践进行处理?谢谢
根据 firestore 的文档,如果您需要实时更新,您应该使用 onSnapshot:
https://firebase.google.com/docs/firestore/query-data/listen
在您的情况下,如果您使用 .get() - 您会获得一次更新,如果任何数据发生更改,firestore 将不会通知您。这就是您没有看到更改的原因。
P.S。 checkout redux-firestore: https://github.com/prescottprue/redux-firestore - 这是一个很好的库,可以帮助你进行 redux 绑定。
您可以这样订阅您的列表:
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
使用 redux-saga
eventChannel
。 eventChannel
收到一个发射器,该发射器会生成一个 saga 效果以供 take
使用。 eventChannel
必须 return 一个函数来关闭连接,但是 afaik .onSnapshot
连接不需要显式关闭,这就是为什么我 return 一个虚拟函数。
我正在尝试找出将 firestore.onSnapshot 与 react-redux 一起使用的正确方法。
我目前在我的操作文件中有这段代码,我在我的组件中调用 componentWillMount()
。
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);
}
};
这工作正常,正确的数据被发送到组件并显示。问题是,如果用户签入,签入数据应该调整,但它没有,因为我只获取一次数据并发送它,并且状态没有重新呈现。
我的问题是我应该如何处理这个问题?我是否使用 .onSnapshot()
而不是 .get()
?我是从 .checkin()
动作创建者那里调用 .fetchCheckins()
吗?我如何根据最佳实践进行处理?谢谢
根据 firestore 的文档,如果您需要实时更新,您应该使用 onSnapshot: https://firebase.google.com/docs/firestore/query-data/listen
在您的情况下,如果您使用 .get() - 您会获得一次更新,如果任何数据发生更改,firestore 将不会通知您。这就是您没有看到更改的原因。
P.S。 checkout redux-firestore: https://github.com/prescottprue/redux-firestore - 这是一个很好的库,可以帮助你进行 redux 绑定。
您可以这样订阅您的列表:
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
使用 redux-saga
eventChannel
。 eventChannel
收到一个发射器,该发射器会生成一个 saga 效果以供 take
使用。 eventChannel
必须 return 一个函数来关闭连接,但是 afaik .onSnapshot
连接不需要显式关闭,这就是为什么我 return 一个虚拟函数。