1. 12
    Redux: Writing a Todo List Reducer (Toggling a Todo)
    2m 47s

Redux: Writing a Todo List Reducer (Toggling a Todo)

InstructorDan Abramov

Share this video with your friends

Send Tweet

Learn how to implement toggling a todo in a todo list application reducer.

Omri Mor
Omri Mor
~ 4 years ago

Thanks for the videos Dan! Very informative and well structured. I try to write the tests first on my own before I watch you do it. Was surprised to see I came up with a solution different than yours. Want to post here for review to see if my solution misses edge cases or has performance issues. Relevant code below :

const todoReducer = (state = [], action) => {
    switch (action.type) {
        case "TOGGLE_TODO":
            return [
                ...state.slice(0, action.id),
                {...state[action.id], isCompleted: !state[action.id].isCompleted},
                ...state.slice(action.id + 1)
            ]
        default:
            return state;
    }
}

thanks!

dan entous
dan entous
~ 4 years ago

change the ids on the todos so they don’t follow a sequential pattern or match their position in the array.

Christian
Christian
~ 3 years ago

Here's a way you could implement immutable updates in a reducer with Immutable.js:

const { List, Record } = Immutable;

const Todo = Record({
  id: 0,
  text: "",
  completed: false
});

const todos = (state = List(), action) => {
  switch (action.type) {
    case "TOGGLE_TODO":
      const index = state.findIndex(todo => todo.id === action.id);
      return state.update(index, todo =>
        todo.update("completed", completed => !completed)
      );
    default:
      return state;
  }
};

const testToggleTodo = () => {
  const stateBefore = List([
    Todo({
      id: 0,
      text: "Learn Redux",
      completed: false
    }),
    Todo({
      id: 1,
      text: "Go shopping",
      completed: false
    })
  ]);
  const action = {
    type: "TOGGLE_TODO",
    id: 1
  };
  const stateAfter = List([
    Todo({
      id: 0,
      text: "Learn Redux",
      completed: false
    }),
    Todo({
      id: 1,
      text: "Go shopping",
      completed: true
    })
  ]);

  expect(todos(stateBefore, action)).toEqual(stateAfter);
};

testToggleTodo();
console.log("All tests passed.");

Because this code is looking up todos by id, a better data structure to store Todos in may be an immutable Map indexed by id.

The toggle_todo action could then be simplified to:

return state.update(action.id, todo =>
  todo.update("completed", completed => !completed)
);