Search code examples
reactjsreduxreact-reduxredux-saga

Implementing CRUD with react-redux


I have googled this type of problem, but they fail to address this type of situation. This is problem i'm facing:
A . There is application which will host serverl crud operations. Lets take User Crud operations for example. User will hape

  1. Create api - (action type: REQUEST, SUCCESS, ERROR).
  2. Update api - (action type: REQUEST, SUCCESS, ERROR).
  3. DELETE api - (action type: REQUEST, SUCCESS, ERROR).
  4. FETCH api - (action type: REQUEST, SUCCESS, ERROR).

Each api has actions as mentioned above to handle loading , success, and failure. How sold one go about create reducer it? Should we create 1 reducer for Users Api that wil handle crud actions of User or 1 reducer per api ? Remember there will be multiple crud apis. This is my current implementation:

const initialState = {
    loading: false,
    data: null,
    error: null
};

const UserReducer= (state = initialState, action) => {
    switch (action.type) {
        case CREATE_USER_REQUEST:
        case UPDATE_USER_REQUEST:
        case DELETE_USER_REQUEST:
        case FETCH_USERS_REQUEST: {
            return {
                ...state,
                loading: true
            };
        }
        case CREATE_USER_SUCCESS:
            return {
                ...state,
                loading: false,
                error: null
            };

        case FETCH_USERS_SUCCESS:
        case UPDATE_USER_SUCCESS:
        case DELETE_USER_SUCCESS: {
            return {
                ...state,
                data: action.payload,
                loading: false,
                error: null
            };
        }
        case FETCH_USERS_FAILURE:
        case CREATE_USER_FAILURE:
        case UPDATE_USER_FAILURE:
        case DELETE_USER_FAILURE: {
            return {
                ...state,
                data: null,
                loading: false,
                error: action.error
            };
        }
        default:
            return state;
    }
};

const reducers = combineReducers({
    api1: api1Reducer,
    userState: UserReducer
});

The problem with above implmentation is that when we create a new user, userState will return loading = true but the other components will not have any idea for whic action, loading is true. for fetching user list or creating a new user ? Same goes if an api has failed.

B. After succesfully creating a new user, we need to fetch the user list. We are using redux-saga for apis.

function* createUser({ payload }) {
    try {
        const firm = yield requestCreateUser(payload);
        yield fetchUserList();
    } catch (error) {
        yield put(
            createBrokerFirmsFailure('Failed to get list of broker firms')
        );
    }
}


function* fetchUserList({ payload }) {
    try {
        const response = yield requestUserList(payload);
        yield put(fetchUserListSuccess(response));
    } catch (error) {
        yield put(
            fetchUserListFailure('Failed to get list of user')
        );
    }
}

As you cna see in the above example, after creating a new user, i'm calling anfter funnction from within the sage itself. This is the correct way to hanlde this issue?


Solution

  • Handling CRUD operations like this is - for examples - handled by "RTK Query" of the official Redux Toolkit, which generates all the actions, reducers etc. for you. It also handles stuff on a per-request basis, not on a per-reducer basis.

    While you can jump directly into that, I would recommend you to look into the official Redux Tutorial first (which in chapters 8 and 9 also covers RTK Query), since you are writing a very outdated style of Redux here, that will make you write about four times the amount of Redux than a modern approach would require you to. Modern Redux does not use switch..case reducers, hand-written action creators, hand-written immutable logic or ACTION_TYPE constants any more.

    https://redux.js.org/tutorials/essentials/part-1-overview-concepts