3

I'm trying to do a delete todo and I want to remove the item from the object "byIds" with the specific id. It will be like a filter for arrays but for the object. I don't know what's so complicated hope for help I believe its stupid

import { ADD_TODO, TOGGLE_TODO, DELETE_TODO } from "../actionTypes";

const initialState = {
  allIds: [],
  byIds: {},
};

export default function (state = initialState, action) {
  switch (action.type) {
    case ADD_TODO: {
      const { id, content } = action.payload;
      return {
        ...state,
        allIds: [...state.allIds, id],
        byIds: {
          ...state.byIds,
          [id]: {
            content,
            completed: false,
          },
        },
      };
    }
    case TOGGLE_TODO: {
      const { id } = action.payload;
      return {
        ...state,
        byIds: {
          ...state.byIds,
          [id]: {
            ...state.byIds[id],
            completed: !state.byIds[id].completed,
          },
        },
      };
    }
    // of course its toggling but it doesn't even get there
    case DELETE_TODO: {
      const { id } = action.payload;
      return {
        ...state,
        allIds: state.allIds.filter((todo) => todo !== id),
        byIds: state.byIds.filter((todo) => todo !== id),
      };
    }
    default:
      return state;
  }
}

{
  todos: {
    allIds: [
      1,
      2,
      3,
      4
    ],
    byIds: {
      '1': {
        content: 'Test1',
        completed: false
      },
      '2': {
        content: 'Test2',
        completed: false
      },
      '3': {
        content: 'test3',
        completed: false
      },
      '4': {
        content: 'test4',
        completed: false
      }
    }
  },
  visibilityFilter: 'all'
}

That for the one who asked me to console log the byIds hope that will help me

3 Answers3

2

What you need is to iterate through the keys of byids object and take only the ones you need.

case DELETE_TODO: {
  const { id } = action.payload;
  let newObj = {}

  Object.keys(state.byIds).forEach(function(key) {
    if (key !== id) {
      newObj[key] = state.byIds[key]
   }
  });
  return {
    ...state,
    allIds: state.allIds.filter((todo) => todo !== id),
    byIds: newObj 
  };
}

In case your id is not a string but a number, you need to check with key != id and not key !== id

Apostolos
  • 10,033
  • 5
  • 24
  • 39
  • @Ethanolle does this help ? – BARNOWL Aug 01 '20 at 17:22
  • Line 42: 'byids' is not defined no-undef Line 44: 'byids' is not defined no-undef –  Aug 01 '20 at 17:23
  • @BARNOWL i like the other answer with destructuring to be honest. my solution is classic js, the others are ES6 style :) – Apostolos Aug 01 '20 at 17:23
  • Line 42: 'byIds' is not defined no-undef Line 44: 'byIds' is not defined no-undef Sanme Probleme –  Aug 01 '20 at 17:27
  • yes of course... it is `state.byIds` not just `byIds`. my mistake – Apostolos Aug 01 '20 at 17:28
  • Nop that just deleting my allIds state but not the byIds. Something that looks so simple that's killing me. –  Aug 01 '20 at 17:31
  • ok so final solution is this. i don;t how what type is your id, but try `key != id` instead of `key !== id` – Apostolos Aug 01 '20 at 17:32
  • Bingo, can you explain to me? because even my vsCode is expecting something else. –  Aug 01 '20 at 17:34
  • `==` will check the value but `===` will check the type too. so if you are trying to compare 1 with "1" and the first will result to true because values are the same and second to false because first is number and second string. same is for `!=` – Apostolos Aug 01 '20 at 17:35
  • 1
    If I see you in the street ill give you a kiss, Thanks sory for being such a young noobie –  Aug 01 '20 at 17:38
0

You can separate the id out like this:

case DELETE_TODO: {
  const id = action.payload.id;
  const { [id]: _, ...filteredState } = state.byIds; 
  // ^ this takes id from state and puts it in variable _,
  // everything else is packed into filteredState

  return {
    ...state,
    allIds: state.allIds.filter((todo) => todo !== id),
    byIds: filteredState,
  };
}

Edit: Extra notes for anyone wondering about the syntax above, see these links:

Computed Property Names, how we are grabbing [id]

Destructuring assignment, how we are packing back into ...filteredState

Awesome comment explaining destructuring

D. Smith
  • 739
  • 5
  • 9
  • Nop that just deleting my allIds state but not the byIds –  Aug 01 '20 at 17:25
  • Ah from reading the other comments it looks like the reason it does not work is because you are passing in a number as `action.payload.id`, but the keys in `byIds` are strings. – D. Smith Aug 01 '20 at 17:58
0

You could use the rest syntax to exclude the id when creating the new object.

case DELETE_TODO: {
  const { id } = action.payload;
  const { [id]: _, ...restByIds } = state.byIds;
  return {
    ...state,
    allIds: state.allIds.filter((todo) => todo !== id),
    byIds: restByIds,
  };
}
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272