0

functional programming has introduced immutable, so es6's map is quite a popular approach when working with data, specifically in arrays and object.

I have a reducer of redux below

const todos = (state = [], action) => {
    switch(action.type) {
        case 'TOGGLE_TODO': {
            return state.map(todo => 
                todo.id !== action.id ? todo 
                : {
                ...todo, checked: !todo.checked
                }
            )
        }
        default:
           return state
    }

}

What's the alternative to change the checked property besides above approach? Is the code even readable at all?

someone prefer this

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;
    }
esther Joo
  • 459
  • 1
  • 5
  • 11
  • There are quite a couple of errors. The case is missing a `:` and the `default` is outside of the `switch` block – NullDev Nov 14 '17 at 09:38
  • Your approach is actually just like [redux's](https://github.com/reactjs/redux/blob/master/docs/recipes/reducers/ImmutableUpdatePatterns.md#updating-an-item-in-an-array) one. So no further changes on that, unless you want it. – Hemerson Carlin Nov 14 '17 at 09:41
  • @mersocarlin why it need item and action.item? that's strange. – esther Joo Nov 14 '17 at 09:43
  • @estherJoo `item` and `action.item`? I don't see that in your code. – Hemerson Carlin Nov 14 '17 at 09:45
  • @mersocarlin I mean in redux's doc, the example you shown me – esther Joo Nov 14 '17 at 10:02
  • if you wish to go with a more elegant and readable approach, please see https://github.com/facebook/immutable-js/wiki/Immutable-as-React-state – Theo Nov 14 '17 at 10:04
  • @estherJoo not every action is the same. You can model your actions as you wish. Redux example has item on it because it wants to update the entire object in the array. Your case, is more specific and toggles `checked` property only. – Hemerson Carlin Nov 14 '17 at 10:07
  • @Theo it's just a library with crud wrapper / api, why everyone is so into immutable.js? – esther Joo Nov 14 '17 at 10:13
  • This answer should help https://stackoverflow.com/questions/45490574/updating-an-object-within-array-in-react-redux-reducer-getting-map-is-not-a-fu/45490835#45490835. You could also think about using immutableJS for your states if your data is highly nested – Shubham Khatri Nov 14 '17 at 10:47
  • @estherJoo Yes Shubham is right. you might want to use it in very good use cases like updating highly nested states. – Theo Nov 15 '17 at 00:50

1 Answers1

0

Here's what I would do;

const todos = (state = [], action) => {
  switch(action.type) {
    case 'TOGGLE_TODO': {
      let newState = state.concat([]);
      newState.any((item) =>
        item.id == action.id && 
          (item = { ...item, checked: !item.checked })
      ); 

      return newState;
    }
    default:
       return state;
  }
}

If you can change the data structure of your todo list to a map, then I think the following looks more readable.

const todos = (state = {}, action) => {
  switch(action.type) {
    case 'TOGGLE_TODO': {
      let itemToChange = state[action.id];
      return { 
        ...state, 
        [action.id]: { 
          ...itemToChange, 
          checked: !itemToChange.checked 
        }
      };
    }
    default:
       return state
  }
}
Raghudevan Shankar
  • 1,083
  • 9
  • 18
  • this is slick too, especially the second one using array's index, no need to go through the entire loop. – esther Joo Nov 17 '17 at 10:27
  • In the second approach, the list of todos is actually just a plain object (not an array) mapping id (of the todo item) to the actual item; if this answer helped you, please consider accepting and upvoting it :) – Raghudevan Shankar Nov 17 '17 at 15:30