Home > database >  Cannot read properties of undefined (reading 'isAuthenticated') at Function.mapStateToProp
Cannot read properties of undefined (reading 'isAuthenticated') at Function.mapStateToProp

Time:08-08

Error says that it reads isAuthenticated as undefined, even though in my global state I have the variable under state.authReducer.isAuthenticated.

I'm using redux and it appears that I can't access the global state (I think the issue lies in store.js but I really don't know what exactly is the issue). Some fellow learner has posted a similiar (maybe identical) issue, but the answers did not help me as it still reads isAuthenticated as undefined.

store.js:

const initialState = {};
const middleware = [thunk];
const store = legacy_createStore(
    rootReducer,
    initialState,
    composeWithDevTools(applyMiddleware(...middleware))
);

export default store;

authReducer:

const initialState = {
    token: localStorage.getItem('token'),
    isAuthenticated: null,
    loading: true,
    user: null,
};

const authReducer = (state = initialState, action) => {
    const { type, payload } = action;

    switch (type) {
        case LOGIN_SUCCESS:
            localStorage.setItem('token', payload.token);
            return {
                ...state,
                ...payload,
                isAuthenticated: true,
                loading: false,
            };
        case LOGIN_FAIL:
            localStorage.removeItem('token');
            return {
                ...state,
                token: null,
                isAuthenticated: false,
                loading: false,
            };
        default:
            return state;
    }
};

Login.js component:

const Login = ({ loginUser, isAuthenticated }) => {
    const [formData, setFormData] = useState({
        email: '',
        password: '',
    });

    const { email, password } = formData;

    const onChange = (e) => {
        setFormData({ ...formData, [e.target.name]: e.target.value });
    };

    const onSubmit = async (e) => {
        e.preventDefault();
        loginUser(email, password);
    };

    // Redirect if logged in
    if (isAuthenticated) {
        return <Navigate to='/dashboard' />;
    }

    return(some JSX form)

Login.propTypes = {
    login: PropTypes.func.isRequired,
    isAuthenticated: PropTypes.bool,
};


const mapStateToProps = (state) => ({
    isAuthenticated: state.auth.isAuthenticated,
});

export default connect(null, { loginUser })(Login);

Edit: I found out that if I set connect() function first parameter to null, the component renders, but if I set the parameter to mapStateToProps it doesn't render (inside the component). Still, my issue is the same: isAuthenticated is undefined.

CodePudding user response:

How are you defining rootReducer?

My guess, without looking, is that you're either treating all of the auth reducer as rootReducer, or calling combineReducers({authReducer}). In either case, there won't be a state.auth field, because your store configuration did not define one.

The short fix here is:

const rootReducer = combineReducers({
  auth: authReducer
}) 

The better answer is to use our official Redux Toolkit package and its configureStore API, instead of the legacy createStore API:

const store = configureStore({
  reducer: {
    auth: authReducer
  }
})
// this added `state.auth`, _and_ the thunk middleware, 
// _and_ the Redux DevTools, in one function call!

You should also be using RTK's createSlice instead of writing reducers by hand.

  • Related