How to use Reselect selectors inside a Redux reducer

burtyish picture burtyish · Aug 7, 2017 · Viewed 9.4k times · Source

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
  }
}

Answer

Yury Tarabanko picture Yury Tarabanko · Aug 7, 2017

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);