Search code examples
reactjsreduxstateredux-thunk

Reducer updates state object which it should not be able to access


The problem is that when on of my reducer updates its own state, it also updates the state of another reducer.

//authActions.js

export const authActions = {
    login: (props) => dispatch => {
        // This will make sure the loading spinner will appear.
        dispatch({
            type: POST_LOGIN_PENDING,
            payload: null
        })
        // make request to login user      
        axios.post(LOGIN_ENDPOINT, {
            email: props.email, 
            password: props.password
        }).then(res => dispatch({
            type: POST_LOGIN_FULFILLED,
            payload: res.data
        })
        ).catch( () => dispatch({
            type: POST_LOGIN_REJECTED,
            payload: null
        }))
    },
    logout: () => dispatch => {
        dispatch({
            type: LOGOUT,
            payload: null
        })
    },

// authReducer.js

export const initialState = {
    token: "",
    userRole: "",
    isLoading: false,
    loginFailed: false,
    isAuthenticated: false,
}

export function authReducer(state = initialState, action) {
    switch (action.type) {
        case POST_LOGIN_PENDING:
            return {
                ...state,
                isLoading: true,
            }
        case POST_LOGIN_FULFILLED:
        return {
            ...state,
            token: action.payload.token,
            userRole: action.payload.userRole,
            loginFailed: false,
            isAuthenticated: true,
            isLoading: false,
        }
        case POST_LOGIN_REJECTED:
            return {
                ...state,
                loginFailed: true,
                isLoading: false,
            }

// studentActions.js

export const studentActions = {
    getAllStudents: props => dispatch => {
        dispatch({
            type: GET_ALL_STUDENTS_PENDING,
            payload: null,
        })
        axios.get(STUDENTS_ENDPOINT, {
            headers: {
                'Authorization': `Bearer ${props.token}`
            }   
        })
        .then(res => 
            dispatch({
            type: GET_ALL_STUDENTS_FULFILLED,
            payload: res.data
        }))
        .catch(err => dispatch({
            type: GET_ALL_STUDENTS_FULFILLED,
            payload: err
        }))
    },

// studentReducer.js

export const initialState = {
    students: [],
    err: "",
    isLoading: false,
}

export function studentReducer(state = initialState, action) {
    switch (action.type) {
        case GET_ALL_STUDENTS_PENDING:
            return {
                ...state,
                isLoading: true,
        }

        case GET_ALL_STUDENTS_FULFILLED:
            return {
                ...state,
                students: action.payload,
                isLoading: false,
        }

        case GET_ALL_STUDENTS_REJECTED:
            return {
                ...state,
                err: action.payload,
                isLoading: false,
        }
        case DELETE_STUDENT_BY_ID_FULFILLED:
            return state
        default:
            return state
    }
}

When a user logs in and the POST_LOGIN_FULFILLED applies. I would expect only the initialstate of the authReducer to be updated, but when inspect with the redux devtools I can see that that the array "studens" which is part of the initialstate of the studentReducer also is updated. From what I understand this should not be possible.

After the user has logged in the students array is filled: (From redux devtools)

student: {
   students: [] => {....some stuff}
   isLoading: true => false
}

Solution

  • By reading you comments it looks like that GET_ALL_STUDENTS_FULFILLED refers to POST_LOGIN_FULFILLED . This must be the reason why your students array is updated. Change

     export const   GET_ALL_STUDENTS_PENDING = 'POST_LOGIN_PENDING';
     export const GET_ALL_STUDENTS_REJECTED = 'POST_LOGIN_REJECTED';
     export const GET_ALL_STUDENTS_FULFILLED = 'POST_LOGIN_FULFILLED'; 
    

    to

     export const GET_ALL_STUDENTS_PENDING = 'GET_ALL_STUDENTS_PENDING ';
     export const GET_ALL_STUDENTS_REJECTED = 'GET_ALL_STUDENTS_REJECTED ';
     export const GET_ALL_STUDENTS_FULFILLED = 'GET_ALL_STUDENTS_FULFILLED '; 
    

    Action types should be unique or else it might get triggered by some other action