React+Redux+Firebase双日历仅能访问一个CloudFirestore集合问题
问题根源
你的问题核心是Redux状态结构设计缺陷:当前calendarSlice里的events是单一数组,两个日历组件加载时,第二个的setEvent会完全覆盖第一个的事件数据,最终状态里只能保留最后加载的集合内容。
解决方案:重构Redux状态结构,按集合名隔离事件
1. 修改calendarSlice的初始状态与reducers
将单一事件数组改为按集合名存储的对象,同时跟踪每个集合的加载状态,区分不同集合的活跃事件:
// calendarSlice.js initialState: { // 键为集合名称,值为对应集合的事件数组 eventsByCollection: {}, // 存储当前活跃事件,包含所属集合名 activeEvent: null, // 结构示例:{ collectionName: 'xxx', event: {...} } // 跟踪每个集合的加载状态 isLoadingByCollection: {}, }, reducers: { onSetActiveEvent: (state, { payload }) => { // payload需包含collectionName和event state.activeEvent = payload; }, onAddEvent: (state, { payload }) => { const { collectionName, event } = payload; // 若集合不存在则初始化空数组 if (!state.eventsByCollection[collectionName]) { state.eventsByCollection[collectionName] = []; } state.eventsByCollection[collectionName].push(event); state.activeEvent = null; }, onUpdateEvent: (state, { payload }) => { const { collectionName, event } = payload; state.eventsByCollection[collectionName] = state.eventsByCollection[collectionName].map(existingEvent => existingEvent.id === event.id ? event : existingEvent ); }, setEvents: (state, { payload }) => { const { collectionName, events } = payload; state.eventsByCollection[collectionName] = events; state.isLoadingByCollection[collectionName] = false; }, // 添加设置加载状态的reducer setLoading: (state, { payload }) => { const { collectionName, isLoading } = payload; state.isLoadingByCollection[collectionName] = isLoading; }, },
2. 调整自定义钩子useCalendarStore的逻辑
更新事件加载、新增、更新的逻辑,传递集合名给action,确保数据存储到对应集合键下:
// useCalendarStore.js const startLoadingEvents = async (collectionName) => { dispatch(setLoading({ collectionName, isLoading: true })); const querySnapshot = await getDocs(collection(db, collectionName)); const events = []; querySnapshot.forEach((doc) => { events.push({ id: doc.id, start: doc.data().start.toDate(), end: doc.data().end.toDate(), title: doc.data().title, notes: doc.data().notes, }); }); dispatch(setEvents({ collectionName, events })); }; // 新增事件逻辑 const startAddNewEvent = async (collectionName, event) => { // 此处保留原有Firebase新增逻辑 const newEvent = await // ...Firebase写入操作 dispatch(onAddEvent({ collectionName, event: newEvent })); }; // 更新事件逻辑 const startUpdateEvent = async (collectionName, event) => { // 此处保留原有Firebase更新逻辑 const updatedEvent = await // ...Firebase更新操作 dispatch(onUpdateEvent({ collectionName, event: updatedEvent })); };
3. 调整日历组件的使用方式
每个日历组件接收collectionName作为props,从Redux中获取对应集合的事件与加载状态:
// CalendarComponent.jsx const CalendarComponent = ({ collectionName }) => { const { eventsByCollection, isLoadingByCollection, activeEvent, startLoadingEvents, startAddNewEvent, startUpdateEvent } = useCalendarStore(); const events = eventsByCollection[collectionName] || []; const isLoading = isLoadingByCollection[collectionName] ?? true; useEffect(() => { startLoadingEvents(collectionName); }, [collectionName, startLoadingEvents]); // 判断当前活跃事件是否属于本集合 const isActiveEventMine = activeEvent?.collectionName === collectionName; const currentActiveEvent = isActiveEventMine ? activeEvent.event : null; return ( <div> {isLoading && <p>加载中...</p>} <BigCalendar events={events} selectable onSelectEvent={(event) => dispatch(onSetActiveEvent({ collectionName, event }))} onSelectSlot={(slotInfo) => {/* 处理新增事件逻辑,调用startAddNewEvent并传入collectionName */}} // 其他配置项 /> </div> ); };
4. 主页面挂载两个日历组件
传递不同的集合名props即可:
// HomePage.jsx const HomePage = () => { return ( <div className="calendars-container"> <CalendarComponent collectionName="你的第一个集合名" /> <CalendarComponent collectionName="你的第二个集合名" /> </div> ); };
修改完成后,两个日历的事件会分别存储在Redux的eventsByCollection对象中,互不覆盖,各自的增删改查操作也只会影响对应集合的事件数据。
内容的提问来源于stack exchange,提问作者guido
相关产品推荐
相关产品推荐

