score:10

Accepted answer

It seems that somehow I am mutating the state.

Correct you are mutating the state, because in js, variable always get reference of object/array. In your case item will have the reference of each object of the array and you are directly mutating the value of item.done.

Another issue is you are not returning the final object properly, also you need to return value for each map iteration otherwise by default it will return undefined.

Write it like this:

case "TOGGLE_TODOS": 
    return list.map((item) => (
        item.index===index? {...item, done: !item.done}: item
    ))

Or:

case 'TOGGLE_TODOS':
    const index = action.index;
    const newState = [ ...state ];
    newState[index] = { ...state[index], done: !newState[index].done };
    return newState;

Full Code:

export default function todoApp(state=[], action){
    switch(action.type){
        case 'ADD_TODO':
            return [...state, action.item];
        case 'TOGGLE_TODOS':
            const index = action.index;
            return state.map((item) => (
                item.index===index? {...item, done: !item.done}: item
            ))
        default:
            return state;    
    }
}

Check this snippet:

let list = [
    {done:true, index:0},
    {done:false, index:1},
    {done: true, index:2}
  ]

let index = 1;

let newList = list.map(item => (
    item.index===index? {...item, done: !item.done}: item
))

console.log('newList = ', newList);

score:0

Although there already exist two correct answers, I'd like to throw lodash/fp in here as well, which is a bit more dense and readable and also doesn't mutate

import { set } from 'lodash/fp'

return list.map(item => {
    if (item.index === index) {
        return set('done', !item.done, item)
    }
    return item
}

score:1

Check out the documentation for Array.prototype.Map.

The callback function should return element of the new Array. Try this:

return list.map(item => {
  if (item.index === index) {
    return {
      done: !item.done
      ...item,
    }

  return item;
});

Related Query

More Query from same tag