简体   繁体   中英

Struggling using react-redux hooks with state

Hello fellow developers,

I'm creating a little app in react native, and i'm using react-redux to store and manage my datas. I've got an events.js reducer registered in my store, using 'events/load' dispatch action to set the initialState in my App.js. It looks like that:

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
  }
}

Now, I have a screen, using SectionList from react native, and I want to display there all the userEvents from my store, previously loaded. The problem is that my useSelector hook only return Promise when i try to get events. If i try to get events.userEvents, it's undefined. Here what it look like:

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
}

When i console log my eventsSelector this is what i've got, so you can see that I have some userEvents. But it's a Promise and i don't really know why...

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,
}

How can I fix this? Do you have any improvment suggestions?

Thank you for your help:)

Edit: Some code about my 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>
  )
};

did you dispatch the events/load action?

/// src/redux/events/eventActions.js

import store from '../store'

function loadEvents() {
  return {
    type: 'events/load'
  }
}

store.dispatch(loadEvents())

A good practice is to create a const for every action like this:

/// 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
  }
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM