简体   繁体   中英

Cannot read properties of undefined (reading 'isAuthenticated') at Function.mapStateToProps

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.

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.

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