1

I'm wondering what is the right way to delete a nested field in redux actions. For example, I have this code:

const SUBSCRIBE = 'SUBSCRIBE';
const UNSUBSCRIBE = 'UNSUBSCRIBE';

export default function reducer(state = {}, action) {
  const {
    productName,
    products,
    componentName
  } = action;
  switch (action.type) {
    case UNSUBSCRIBE: {
      if (state[productName]?.[componentName]) {
        const newState = { ...state };
        delete newState[productName][componentName];
        return newState;
      } else {
        return state;
      }
    }
    default:
      return state;
  }
}


export function unsubscribe(productName, componentName) {
  return {
    type: UNSUBSCRIBE,
    productName,
    componentName
  };
}

In UNSUBSCRIBE action I delete newState[productName][componentName] field, however this will also delete the field on the "old" state. So theoretically if there're other actions which use this field it may be lost for them because the state is mutated. Should I deep copy old state into newState and then delete newState[productName][componentName]?

hitchhiker
  • 1,099
  • 5
  • 19
  • 44

1 Answers1

1

You can do one of two:

  1. create a copy of a productName state and delete componentName from that copy
if (state[productName]?.[componentName]) {
  const newProductState = { ...state[productName] };
  delete newProductState[componentName];
  return {
    ...state,
    [productName]: newProductState
  };
} else {
  return state;
}
  1. Instead of deletion, you can mark the componentName as undefined (which I would personaly prefer to do)
if (state[productName]?.[componentName]) {
  return {
    ...state,
    [productName]: {
      ...state[productName],
      [componentName]: undefined,
    },
  };
} else {
  return state;
}
Rostyslav
  • 2,606
  • 9
  • 17
  • but is there any risk to delete the property using `delete`? redux actions can't be executed in parallel anyway right? (because Javascript is single threaded) – hitchhiker Nov 12 '20 at 08:41
  • 1
    @hitchhiker when you copy part of the object and `delete` from that part like in example #1 there is no danger. Actions can be dispatched both synchronously and asynchronously but it doesn't matter. Redux actions, regardless of the way they had been dispatched, are being handled by the reducer function which is synchronous by definition. – Rostyslav Nov 13 '20 at 21:36
  • So why is it better to not use `delete` as in your examples? – hitchhiker Nov 22 '20 at 09:00
  • 1
    @hitchhiker as I believe, your intent here was to clean up the unused property to optimize memory. However, `delete` has nothing to do with memory optimization. To remove an object from memory in JS, all references to it have to be removed or out-scoped. Please, see [this answer](https://stackoverflow.com/questions/25457518/how-to-correctly-dereference-then-delete-a-javascript-object) – Rostyslav Nov 22 '20 at 11:03
  • I guess `delete` is bad because an update will not be generated. That is sub-object has changed because it lost one of its fields however subscribers to the changes on the sub-object will not be notified because it's the same sub-object (the reference didn't change). In your case the reference changes so the subscribers will be notified of the changes. I guess that the only reason to use your suggestion – hitchhiker Nov 22 '20 at 11:30
  • 1
    @hitchhiker in general yes. But it depends on your selectors. If they rely on the whole state object (the reference to it changes) the change should be reflected – Rostyslav Nov 22 '20 at 11:38