Search code examples
reactjstypescriptredux

useSelector returns undefined in react


I am using React + TypeScript for development and using Redux for centralised state management - to store the current user logged in.

Here is the userReducer:

import {createSlice , PayloadAction} from '@reduxjs/toolkit';

const initialState = {
    name:"john",
    email:"Doe",
};

const userSlice = createSlice({
    name:'user',
    initialState,
    reducers:{
        setUserName(state,action:PayloadAction<string>){
            state.name = action.payload
        },
        setUserEmail(state,action:PayloadAction<string>){
            state.email = action.payload
        }
    }
});
export const {setUserName,setUserEmail} = userSlice.actions;

const userReducer = userSlice.renducer
export default userReducer;

Here is the store:

import { configureStore, combineReducers } from '@reduxjs/toolkit';
import userReducer from '../features/userSlice';

export const store = configureStore({
    reducer:{
        user:userReducer,
    },
});

// Export the store's type
const rootReducer = combineReducers({userReducer});
export type RootState = ReturnType<typeof rootReducer>;

// Export `dispatch`'s return type
export type AppDispatch = typeof store.dispatch

Here is the snippet of code inside my React component, where I try to access the user state:

import { useSelector, useDispatch } from 'react-redux';
import { setUserName, setUserEmail } from '../../features/userSlice';
import { RootState, AppDispatch } from '../../store/store';
export default function Login(){
    const user = useSelector((store:RootState) => store.userReducer);
    console.log("user: "+ user);   
}         

I'm not sure why useSelector returned undefined since I have defined an initialState in the userReducer.


Solution

  • Because you defined the root state as {user}. In other words, the userReducer's data is attached to the root state as state.user.

    So, your selector needs to be state => state.user.

    You also have a problem in your store file. You've created another reducer function with const rootReducer = combineReducers({userReducer}), and then inferred the RootState type from that.

    That is wrong in two ways:

    • That reducer function is not being used at all! configureStore already made its own root reducer function from the definition you provided and is using that
    • Your RootState type is wrong, because it's being inferred from the wrong function

    That's why you're not even getting a TS error here.

    Instead, you need to delete the combineReducers line, and then do:

    type RootState = ReturnType<typeof store.getState>
    

    per our TS usage docs: