Home > Mobile >  Redux useSelector returns nothing in child component
Redux useSelector returns nothing in child component

Time:03-25

I am new to React Native and Redux, and was hoping someone could help out in my issue? I have a parent component that fetches some user data (their location) and dispatches to a redux store:

Parent

import { useDispatch } from 'react-redux'
import { setLocation } from './store/locationSlice'

const App = () => {
  const dispatch = useDispatch()
  
  const getLocation = () => {
    const location = await fetchLoc()
    dispatch(setLocation(location))
  }
  
  useEffect(() => {
    getLocation()
  },[])
 
}

My child component is intended to retrieve this data using the useSelector hook

Child

import { useSelector } from 'react-redux'

const HomeScreen = () => {
  const location = useSelector(state => state.location)
  
  useEffect(() => {
    if (location) {
      getEntitiesBasedOnLocation(location)
    }
    
  },[location])
}

However, in my case, useSelector never retrieves the up-to-date information that i have dispatched in the parent, with location returning undefined. I'm fairly certain there's a simple oversight here, but i'm at a loss as to what this could be. I was under the impression that useSelector subscribes to state changes, so why is it that that my dispatched action that causes a change of state is ignored? Using my debugger, I can see that my state is definitely updated with the correct data, but the child component doesn't pick this up..

Here's my location slice:

import { createSlice } from '@reduxjs/toolkit'

const initialState = {
  location: {
    id: null,
    name: null,
    latitude: null,
    longitude: null
  }
}

const locationSlice = createSlice({
    name: 'location',
    initialState,
    reducers: {
        setLocation: (state, action) => {
            const { id, name, latitude, longitude } = action.payload
            state.location = { id, name, latitude, longitude }
        }
    }
})

export const { setLocation } = locationSlice.actions
export default locationSlice.reducer

UPDATE The store is configured by wrapping the App.js component in a Provider component, with the store passed as its props as follows:

Root.js

import { configureStore } from '@reduxjs/toolkit'
import { Provider } from 'react-redux'
import locationReducer from './src/store/locationSlice'
import App from './src/App'

const Root = () => {
 const store = configureStore({ reducer: locationReducer })
 return (
  <Provider store={store)>
    <App />
  </Provider>
 )
}

CodePudding user response:

The issue is in your selector. You've created the slice called 'location' and within that slice you've got your state { location: {...}}. So from the perspective of the selector (which accesses your global state, not just the location slice) the path to your data would be state.location.location. But your selector is trying to read out of state.location which only has a location prop. Anything else you tried to read out would be undefined.

CodePudding user response:

It is common to export a custom selection function from the slice configuration. Remember that the selector must take exactly the data that you want to share in your component tree (locationSlice.state.location in this case). This is not mandatory, it is just to facilitate development.

// locationSlice 

import { createSlice } from '@reduxjs/toolkit'

//...

export const { setLocation } = locationSlice.actions
export const selectLocation = (state) => state.location.location
export default locationSlice.reducer
// Child
import { useSelector } from 'react-redux'
import {selectLocation} from './src/store/locationSlice'

const HomeScreen = () => {
  const location = useSelector(selectLocation)
  
  //...
}
  • Related