Search code examples
reduxreselect

How to use Reselect selectors inside a Redux reducer


My app already has a large collection of selectors used by the various container objects. These are great for accessing different parts of the state and make refactoring the state much easier.

Now I want to use my selectors inside some of my reducer functions. The problem is that inside the reducer, the state parameter refers to a specific slice of the state, whereas the selector functions expect to be called with the state root object.

Contrived Example:

/* Selectors */
const getTodos = state => state.todos;

const getUncompletedTodos = createSelector(
    [ getTodos ],
    todos => todos.filter(t => !t.completed)
);

/* Reducer */
const todosReducer = (state, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          id: action.id,
          text: action.text,
          completed: false
        }
      ];
    case 'REMOVE_COMPLETED_TODOS':
      return getUncompletedTodos(state); // <-- this won't work
  }
}

Solution

  • You selector works from root state object.

    To fake this you could do

     return getUncompletedTodos({todos: state});
    

    But IMHO a better idea would be to reuse filtering function

    /* Selectors */
    const getTodos = state => state.todos;
    
    const filterCompleted = todos => todos.filter(t => !t.completed)
    
    const getUncompletedTodos = createSelector(
        [ getTodos ],
        filterCompleted
    );
    
    // inside reducer
    case 'REMOVE_COMPLETED_TODOS':
        return filterCompleted(state);