React/Redux, chain or promise in reducer

2019-05-29 05:09发布

问题:

I have a react/redux app where I have some filtering and searching. Because of how the API's are set up, I have to do a little ground work in between receiving the filters and then sending the new search query. So I have a small reference map of the active filters that updates each time I check or uncheck a filter. The problem is, I would like the action to run that updates the filter, and then the action to call the server with the new filter parameters after that, and I am unsure how this workflow is suppose to go in redux.

So I call the action, then it hits the reducer with an updated state like so -

 case actions.TOGGLE_FILTER:
            return toggleFilter(state, action);


var toggleFilter = function(state, action){
var currentFilters = state.toJS().activeFilters || {};
var removeFilterFromActive = function(item) {
    if(item != action.filter.search){
        return;
    }
}
//already exists, remove from list (toggle off)
if (currentFilters[action.filterGroup.parentSearch] && currentFilters[action.filterGroup.parentSearch].indexOf(action.filter.search) > -1) {
    var itemIndex = currentFilters[action.filterGroup.parentSearch].indexOf(action.filter.search);
    currentFilters[action.filterGroup.parentSearch].splice(itemIndex, 1);
} else {
    //add to obj
    var newObj = {};
    if (currentFilters[action.filterGroup.parentSearch]) {
        currentFilters[action.filterGroup.parentSearch].push(action.filter.search);
    } else {
        newObj[action.filterGroup.parentSearch] = [];
        newObj[action.filterGroup.parentSearch].push(action.filter.search);
        _.extend(currentFilters, newObj);
    }
}
return state.set('activeFilters', fromJS(currentFilters));
};

So this assembles my activeFilters state, seems to be working ok for now. But the part I can't figure out, is how to have the call the server with using my updated activeFilters. Right now I am just calling this action from the component it is being used in.

Is there a way to chain, or promise, or dispatch another action inside the reducer when this one has completed? Any advice in how to approach this would be much appreciated. Thanks!

回答1:

Reducers should be pure with no side effects, so you don't want your reducers firing requests to the server or issuing additional actions.

If you are using redux-thunk, then you can dispatch functions as actions. These functions can examine the state of the store. These functions can themself dispatch multiple regular actions. And, if you aren't doing any sort of batching of your Redux updates, they can examine the store after they dispatch an action and then do more stuff.

With the above in mind, you can do something like this:

function createToggleFilterAndQueryServerAction(filterGroup, filter) {
    return (dispatch, getState) => {
        // first dispatch the filter toggle
        // if you do not have any batching middleware, this
        // should run the reducers and update the store
        // synchronously
        dispatch(createToggleFilter(filterGroup, filter));

        // Now get the updated filter from the store
        const activeFilter = getState().activeFilter;

        // now query the server
        callServer(activeFilter).then(result => {
            // Now dispatch an action with the result from the server
            dispatch(createServerResponseAction(result));
        });
    };
}

Usage:

dispatch(createToggleFilterAndQueryServerAction(..., ...));