I am maintaining an array of DiaryEntries as a state and I want to update that list with Diary Entries stored in the firesore database. entries array gets printed correctly but the state does not get updated. what is wrong with my code?
diaryReducer.ts
interface DiaryEntry {
title: string;
description: string;
}
const diarySlice = createSlice({
name: "diary",
initialState: {
entries: [],
currentEntry: {title: "", description: ""}
}as DiaryState ,
reducers: {
getEntry(){},
getDiary(state,acion){
state.entries = acion.payload;
},
diarySaga.ts
function* addDiarySaga(action: any) {
const { title, description } = action.payload;
yield addDoc(diaryRef, { title, description });
}
function* getDiarySaga() {
try{
let entries:any = [];
const unsubscribe = onSnapshot(diaryRef, (querySnapshot) => {
querySnapshot.docs.forEach((doc)=>{
let title = doc.data().title;
let description = doc.data().description
let diary= {
title: title,
description: description
}
entries.push(diary)
})
});
console.log(entries);
yield put(getDiary(entries));
}
catch(error) {
console.log(error);
}
}
export function* diarySaga() {
yield takeLatest("diary/addEntry", addDiarySaga);
yield takeLatest("diary/getEntry", getDiarySaga);
}
Data is loaded from Firestore (and most modern cloud APIs) asynchronously. To prevent blocking the browser/app during this time, the loading happens in the background and the main code continues to execute. This means that your
yield put(getDiary(entries))happens before any data is loaded.The solution for this is always the same: any code that requires the data has to be *inside the
onSnapshotcallback that gets called when the data is available. So in your case: the call toput(getDiary(entries))needs to be inside the callback.So:
That probably means that you can't use
yieldon it, so you may have to figure out what you actually want to return.