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

使用react-redux hooks时useSelector返回Promise、userEvents为undefined如何解决

问题根本原因

Redux要求reducer必须是无副作用的纯函数,不支持直接在reducer内部写异步逻辑。你给eventsReducer加了async关键字,导致reducer返回的是Promise对象,而非正常的state对象,这就是useSelector拿到Promise、访问userEvents报错的核心原因。

修复步骤

1. 重构reducer,移除异步逻辑

把reducer改成纯函数,只负责根据action更新state,删除async关键字和内部的firestore查询逻辑:

import { auth, firestore } from '../lib/firebase'

const initialState = {
  events: [],
  userEvents: []
}

export default function eventsReducer(state = initialState, action) {
  switch (action.type) {
    case 'events/set':
      return {
        ...state,
        events: action.payload
      }
    case 'userEvents/set':
      return {
        ...state,
        userEvents: action.payload
      }
    default:
      return state
  }
}

2. 新增异步action处理数据拉取

用redux-thunk(redux默认支持的异步中间件)封装异步查询逻辑,编写对应的thunk函数:

// 异步拉取活动列表的thunk action
export const loadEvents = () => async (dispatch) => {
  const userId = auth.currentUser.uid
  const eventsData = []
  const userEventsData = []

  // 两个查询并行执行,提升性能
  const [queryEvents, userEvents] = await Promise.all([
    firestore.collection("events").where("userId", "!=", userId).get(),
    firestore.collection("events").where("userId", "==", userId).get()
  ])

  queryEvents.forEach(ev => {
    eventsData.push({ id: ev.id, ...ev.data() })
  })
  userEvents.forEach(ev => {
    userEventsData.push({ id: ev.id, ...ev.data() })
  })

  // 触发reducer更新state
  dispatch({ type: 'events/set', payload: eventsData })
  dispatch({ type: 'userEvents/set', payload: userEventsData })
}

3. 修改App.js的dispatch逻辑

把原来直接dispatchevents/load的代码改成调用上面的thunk action:

// 原代码 await dispatch({ type: 'events/load' }) 替换为
await dispatch(loadEvents())

4. 修复Manage组件的逻辑

  • 把userEvents加到useEffect依赖数组,保证state更新后能重新计算活动列表
  • 修复代码中未定义的doc.id变量(应该用event.id)
const Manage = ({navigation}) => {
  const [loading, setLoading] = React.useState(true);
  const [events, setEvents] = React.useState([]);
  const eventsSelector = useSelector((state) => state.events)
  const { userEvents } = eventsSelector || {}

  useEffect(() => {
    if (!userEvents) return
    const storedEventsIds = new Set() // 用Set判断重复性能更好
    const comingEvents = []
    const passedEvents = []

    userEvents.forEach(event => {
      if (storedEventsIds.has(event.id)) return
      const dateTimeStart = new Date(`${event.dateStart} ${event.timeStart}`)
      const dateTimeEnd = new Date(`${event.dateEnd} ${event.timeEnd}`)
      const dateNow = new Date()

      if (compareAsc(dateTimeStart, dateNow) >= 0 ||
        (compareAsc(dateTimeStart, dateNow) < 0 && compareAsc(dateTimeEnd, dateNow) >= 0)) {
        comingEvents.push({...event, passed: false})
      } else {
        passedEvents.push({...event, passed: true})
      }
      storedEventsIds.add(event.id)
    })

    setEvents([{
      title: "Événements à venir",
      data: comingEvents
    }, {
      title: "Événéments passés",
      data: passedEvents
    }]);
    setLoading(false)
  }, [userEvents]) // 依赖userEvents,数据更新后自动重新计算
  
  // 其余组件代码
}
优化建议
  • 优先使用Redux Toolkit开发Redux逻辑,内置了thunk、immutable更新等能力,大幅减少样板代码,也能避免这类reducer异步的低级错误
  • 可以把活动的已结束/未开始分类逻辑放到useSelector里计算,不用维护本地state,减少重复数据
  • 建议给store添加loading、error状态,统一处理异步请求的加载和异常情况,不用每个组件单独维护加载状态

内容的提问来源于stack exchange,提问作者Bloodbee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 11:36:01