【问题标题】:Struggling using react-redux hooks with state使用带有状态的 react-redux 钩子苦苦挣扎
【发布时间】:2021-11-27 11:35:59
【问题描述】:

各位开发者您好,

我正在用 react native 创建一个小应用程序,我正在使用 react-redux 来存储和管理我的数据。我在我的商店中注册了一个 events.js 减速器,使用“事件/加载”调度操作在我的 App.js 中设置初始状态。看起来是这样的:

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

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

export default async function eventsReducer(state = initialState, action) {
  switch (action.type) {
    case 'events/load': {
      const userId = auth.currentUser.uid
      const eventsData = []
      const userEventsData = []
      // starts with other events
      const queryEvents = await firestore.collection("events").where("userId", "!=", userId).get()
      if (queryEvents) {
        queryEvents.forEach(ev => {
          eventsData.push(Object.assign({}, { id: ev.id }, ev.data()))
        })
      }
      // user events
      const userEvents = await firestore.collection("events").where("userId", "==", userId).get()
      if (userEvents) {
        userEvents.forEach(ev => {
          userEventsData.push(Object.assign({}, { id: ev.id }, ev.data()))
        })
      }

      return {
        ...state,
        events: eventsData,
        userEvents: userEventsData
      }
    }
    case 'events/set': {
      // Set the classics events
      return {
        ...state,
        events: action.payload
      }
    }
    case 'userEvents/set': {
      // Set the userEvents
      return {
        ...state,
        userEvents: action.payload
      }
    }
    default:
      return state
  }
}

现在,我有一个屏幕,使用来自 react native 的 SectionList,我想在那里显示我商店中的所有 userEvents,之前加载。问题是我的 useSelector 挂钩仅在我尝试获取事件时返回 Promise。如果我尝试获取 events.userEvents,它是未定义的。 这是它的样子:

const Manage = ({navigation}) => {
  const [loading, setLoading] = React.useState(true);
  const [events, setEvents] = React.useState([]);
  const eventsSelector = useSelector((state) => state.events)
  
  // use effect one time
  useEffect(() => {
    async function loadDatas() {
      console.log('events selected', eventsSelector) // what i've got in my events ?

      // get the datas for coming events
      const storedEventsIds = []
      const comingEvents = []
      const passedEvents = []

      if (eventsSelector !== null) {
        eventsSelector.userEvents.forEach(event => { // <= THIS IS NOT WORKING - error : Cannot read properties of undefined (reading 'forEach')

          // compare dates to know if it's a coming or passed event
          const dateTimeStart = new Date(`${event.dateStart} ${event.timeStart}`)
          const dateTimeEnd = new Date(`${event.dateEnd} ${event.timeEnd}`)
          const dateNow = new Date()
    
          if (!(doc.id in storedEventsIds)) {
            if (compareAsc(dateTimeStart, dateNow) >= 0 ||
            (compareAsc(dateTimeStart, dateNow) < 0 && compareAsc(dateTimeEnd, dateNow) >= 0)) {
              comingEvents.push(Object.assign({}, event, {id: doc.id, passed: false}))
              storedEventsIds.push(doc.id)
            } else {
              passedEvents.push(Object.assign({}, event, {id: doc.id, passed: true}))
              storedEventsIds.push(doc.id)
            }
          }
        })
      }
  
      // set events
      setEvents([{
        title: "Événements à venir",
        data: comingEvents
      }, {
        title: "Événéments passés",
        data: passedEvents
      }]);
      setLoading(false)
  
    };
    loadDatas()
  }, [])
  
  // ... omitted manage component code - basically only html
}

当我控制台记录我的 eventsSelector 这就是我所拥有的,所以你可以看到我有一些 userEvents。但这是一个承诺,我真的不知道为什么......

events selected Promise {
  "_U": 0,
  "_V": 1,
  "_W": Object {
    "_U": 0,
    "_V": 1,
    "_W": Object {
      "events": Array [],
      "userEvents": Array [],
    },
    "_X": null,
    "events": Array [],
    "userEvents": Array [
      Object {
        "coverImage": null,
        "dateEnd": "04/02/2022",
        "dateStart": "04/11/2021",
        "description": "Hbzbwkks
Sjjdjdjdjd
Wjdkkdieizhdbf
Sjjdjdjdjd",
        "id": "ewPrFzAqQmusKrsqQnSP",
        "maxLimit": null,
        "online": true,
        "openPrice": false,
        "place": null,
        "price": 50,
        "secretPlace": false,
        "timeEnd": "17:25",
        "timeStart": "17:25",
        "title": "Mon super event",
        "userId": "pPL2g7bWDYZDzUGtlGCSyLOQ3WK2",
        "website": "https://bloodbee.space",
      },
      Object {
        "dateEnd": "05/10/2021",
        "dateStart": "04/10/2021",
        "description": "La teuf de l'année - 24h de folie ouais :)",
        "id": "gSlmysO0KffkjGKyP9fR",
        "maxLimit": 3000,
        "online": false,
        "openPrice": false,
        "place": "Puy du pariou",
        "price": 30,
        "secretPlace": true,
        "timeEnd": "23:00",
        "timeStart": "23:00",
        "title": "Rave party de l'année",
        "userId": "pPL2g7bWDYZDzUGtlGCSyLOQ3WK2",
        "website": null,
      },
    ],
  },
  "_X": null,
}

我该如何解决这个问题?您有什么改进建议吗?

感谢您的帮助:)

编辑: 关于我的 App.js 的一些代码

const AppWrapped = () => {
  const [appIsReady, setAppIsReady] = useState(false);
  const [signedIn, setSignedIn] = useState(false);

  const dispatch = useDispatch()
  
  const loadApp = async () => {
    // Manage auth
    await auth.onAuthStateChanged( async (user) => {
      if (user) {        
        // Log the user
        await dispatch({ type: 'users/set', payload: user })
        
        // dispatch to get events
        await dispatch({ type: 'events/load' })

        // User is signed in, see docs for a list of available properties
        // https://firebase.google.com/docs/reference/js/firebase.User
        setSignedIn(true)
      } else {
        // User is signed out
        await dispatch({ type: 'users/set', payload: null })
        setSignedIn(false)
      }
    })
  }

  if (!appIsReady) {
    return (
      <AppLoading
          startAsync={loadApp}
          onFinish={() => setAppIsReady(true)}
          onError={console.warn}
          autoHideSplash={true}
        />
    )
  } else {
    // omitted html - when the app is ready - no more splashscreen
  }
};

const App = () => {
  return (
    <StoreProvider store={store}>
      <PaperProvider theme={theme}>
        <AppWrapped />
      </PaperProvider>
    </StoreProvider>
  )
};

【问题讨论】:

    标签: javascript react-native redux react-redux react-hooks


    【解决方案1】:

    您是否调度了事件/加载操作?

    /// src/redux/events/eventActions.js
    
    import store from '../store'
    
    function loadEvents() {
      return {
        type: 'events/load'
      }
    }
    
    store.dispatch(loadEvents())
    
    

    一个好的做法是像这样为每个动作创建一个常量:

    /// src/redux/events/eventTypes.js
    
    const LOAD_EVENTS = 'events/load';
    
    /// src/redux/events/eventActions.js
    
    import store from '../store'
    import { LOAD_EVENTS } from './eventTypes.js'
    
    function loadEvents() {
      return {
        type: LOAD_EVENTS
      }
    }
    
    store.dispatch(loadEvents())
    
    /// src/redux/events/eventReducer.js
    
    import { LOAD_EVENTS } from './eventTypes.js'
    
    const initialState = {
      events: [],
      ...
    }
    
    export default async function eventsReducer(state = initialState, action) {
      switch (action.type) {
        case LOAD_EVENTS: {
          
          ... Some code
    
          return {
            ...state,
            events: eventsData,
            userEvents: userEventsData
          }
        }
        default:
          return state
      }
    } 
    

    【讨论】:

    • 顺便补充一句:一般情况下,使用字符串类型常量的做法已经过时,不再推荐。现代 Redux 在内部将字符串类型作为实现细节处理,您根本不必再编写它们。为了快速了解我推荐阅读redux.js.org/tutorials/fundamentals/part-8-modern-redux,对于更长的教程我推荐redux.js.org/tutorials/essentials/part-1-overview-concepts的完整官方Redux“基本”教程
    • 感谢您的回答。作为回应,是的,我在我的 App.js 中发送了我的事件/加载操作,正如我之前在问题中所说的那样。我的状态中有一些事件(请参阅我的控制台日志)。然后,关于您提供的文档,有一些很好的基础知识,但都是关于我没有使用的 redux 工具包。我已经用我的一些 App.js 代码更新了我的问题。
    • 更新:现在看起来真的很难在没有 RTK 的情况下只使用 react-redux。耻辱,因为它放了更复杂的逻辑代码。无论如何,我设法做到了我想要的。
    • 谢谢@phry,我没注意到。我会将它应用到我未来的项目中。
    • @MathieuDfr Redux Toolkit 是您自 2019 年以来编写的任何 Redux 代码的官方推荐。此时它基本上 Redux。如果您不使用它,是的,您将面临人们在 2019 年之前遇到的所有问题以及创建 Redux Toolkit 的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多