Search code examples
reactjsreact-reduxredux-thunk

Why redux store only get value of last dispatch Action


I am trying to make multi dispatch action in the action phase of redux:

Here is my code:

export const get_data_time_slot_week = (params) => {
return async (dispatch) => {
    dispatch({
        type: common.CALL_API_REQUEST,
    });
    const res = await callAPI.post(TIME_SLOT_WEEK + GET, {
        params: { ...params },
    });

    if (res.status === 200 && res.data.code >= 0) {

//Here, I get new state of Selector timeSlotWeek
        dispatch({
            type: timeSlotWeek.GET_DATA_TIME_SLOT_WEEK_SUCCESS,
            payload: {
                data: [...res.data.data],
                dataPage: { ...res.data.dataPage },
                errCode: res.data.code,
            },
        });

//And here, I lost state of a Selector timeSlotWeek add get new state of Selector common
        dispatch({
            type: common.GET_FEEDBACK,
            payload: {
                msg: "__msg_can_not_to_server",
            },
        });
    }
};

};

Why did it happen? And how can i keep the state of timeSlotWeek with same flow in my code ?

This is my result when i check by Redux tool

GET_DATA_TIME_SLOT_WEEK_SUCCESS     =>    data: { 0: {...}, 1{...} }
GET_FEEDBACK                        =>    data: {}
                                          msg: "new msg"

This is my store.js

import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import rootReducer from "./reducers";
import thunk from "redux-thunk";
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));

export default store;

This is my {combineReducers}

import { combineReducers } from "redux";
import feedback from "./feedback.reducer";
import loadingReducer from "./loading.reducer";
import timeSlotWeek from "./timeSlotWeek.reducer";

const rootReducer = combineReducers({
    dataTimeSlotWeek: timeSlotWeek,
    loading: loadingReducer,
    feedback: feedback,
});

export default rootReducer;

Thanks for your help

UPDATE: Problem solve: Because in my reducer of timeSlotWeek.reducer I have a default case, and when I dispatch another action, this case will run and make the state of timeSlotWeek become initState.

import { common, timeSlotWeek } from "../actions/constants";
const initState = {
    data: [],
};

    export default (state = initState, action) => {
        switch (action.type) {
            case timeSlotWeek.GET_DATA_TIME_SLOT_WEEK_SUCCESS:
                state = {
                    // Pass payload to this
                };
                break;
            default:
                state = { ...initState };
        }
        return state;
    };

I fix it by this way:

import { common, timeSlotWeek } from "../actions/constants";

const initState = {
    data: [],
};

export default (state = initState, action) => {
    switch (action.type) {
        case timeSlotWeek.GET_DATA_TIME_SLOT_WEEK_SUCCESS:
            state = {
                // Pass payload to this
            };
            break;
        **case common.CALL_API_FINISH:
            state = state;
            break;
        case common.GET_FEEDBACK:
            state = state;
            break;**
        default:
            state = { ...initState };
    }
    return state;
};

Have any way better than my way ? Thank for cmt


Solution

  • The default reducer case should always return the current state object. I can't think of a single counter-example otherwise (though I have seen some tutorials throw an error here you generally don't want to do that as it adds unnecessary error handling and complicates everything).

    You need only define cases for actions your state slice reducer needs to handle, otherwise the let the default case handle it by simply returning the current state.

    const initState = {
      data: [],
    };
    
    export default (state = initState, action) => {
      switch (action.type) {
        case timeSlotWeek.GET_DATA_TIME_SLOT_WEEK_SUCCESS:
          return {
            // Pass payload to this
          };
    
        default:
          return state;
      }
    };
    

    If you need to reset some state then use another action and case for this, i.e.:

    case 'resetTimeSlotWeek':
      return initState;