2

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!

ajmajmajma
  • 13,712
  • 24
  • 79
  • 133

1 Answers1

8

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(..., ...));
Brandon
  • 38,310
  • 8
  • 82
  • 87
  • The server calls are all setup in a middleware for me - it checks a specific value on each each action and intercepts. So for the query part you have there, can I just dispatch the second action? Thanks! – ajmajmajma Dec 29 '15 at 15:38
  • Sure. Just dispatch the action with the updated filter – Brandon Dec 29 '15 at 15:57
  • Thank you for answering this, this is all still new to me and a bit overwhelming. One last question - My state is using immutablejs, and I noticed you are passing in getState, will this still work with immutable? – ajmajmajma Dec 29 '15 at 16:15
  • 1
    `getState` will give you the contents of the redux store. So if you are putting immutable objects into the store, then `getState()` will return those immutable objects. – Brandon Dec 29 '15 at 16:36