You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 11:43:20