Eric Bishard
Eric Bishard

Reputation: 5331

Using React Hooks useReducer, how can I update an object by ID efficiently?

I have a StackBlitz that you can fork, I found a similar answer but I'm having trouble applying it to my example, I think it's because I have an array of objects.

I have the code working but it's very verbose, and I would like something easier to read that others who use Redux will recognize.

const initialState = [];
const todoReducer = (state, action) => {
  switch (action.type) {
    case 'ADD_TODO': {
      return [...state, {
        id: state.length,
        name: action.name,
        complete: false
      }];
    }
    case 'TOGGLE_COMPLETE': {
      let left = state.filter((_, index) => index < action.index)
      let right = state.filter((_, index) => index > action.index)
      let completed = state.filter((_, index) => index == action.index)
      let updatedItem = {
        id: completed[0].id,
        name: completed[0].name,
        complete: !completed[0].complete
      }
      return [...left, updatedItem, ...right];
    }
    case 'CLEAR': {
      return initialState;
    }
    default: {
      return state;
    };
  }
}

I feel like the answer is is similar to this one? Update array object in React Redux reducer

In the answer I cited above, his object has state.posts How can I update my example to be more like this one?

How can I target my Todos if I don't have a similar state object as I can't do something like:

state.todos.complete = false.

I want to write a better reducer for the 'COMPLETE' action. Do I need to modify how my state is structured, ie dopes it need to be an empty object instead of an array of objects?

Upvotes: 3

Views: 3259

Answers (1)

Damon
Damon

Reputation: 4336

Just map:

case 'TOGGLE_COMPLETE': {
  return state.map((item, i) => i === action.index 
    ? {...item, complete: !item.complete}
    : item
  )
}

You can conditionally update "complete" without iterating multiple times.

Upvotes: 7

Related Questions