Redux deep clone – state is always equal

Tags: , , ,



I have the following reducer in React Redux:

export const reducer = (state = initialStateData, action) => {
    switch (action.type) {
      case Action.TOGGLE_ARR_FILTER:
        {
          const subArr = state.jobOffers.filters[action.key];
          const filterIdx = subArr.indexOf(action.value[0]);
          const newArr = { ...state.jobOffers.filters
          };

          if (filterIdx !== -1) {
            newArr[action.key].splice(filterIdx, 1);
          } else {
            newArr[action.key].push(action.value[0]);
          }

          return {
            ...state,
            jobOffers: {
              ...state.jobOffers,
              filters: {
                ...newArr,
              },
            },
          };
        }

And this is my object:

const initialStateData = {
  jobOffers: {
    filters: {
      employments: [],
      careerLevels: [],
      jobTypeProfiles: [],
      cities: [],
      countries: [],
    },
    configs: {
      searchTerm: '',
      currentPage: 1,
      pageSize: 5,
    },
  },
};

The reducer as such seems to work, it toggles the values correctly.

But: Redux always shows “states are equal”, which is bad as it won’t recognize changes.

Can someone help ? I assume that I am returning a new object..

Answer

Although you take a copy of state.jobOffers.filters, this still holds references to original child arrays like employments. So when you mutate newArr[action.key] with splice or push, Redux will not see that change, as it is still the same array reference.

You could replace this:

if (filterIdx !== -1) {
  newArr[action.key].splice(filterIdx, 1);
} else {
  newArr[action.key].push(action.value[0]);
}

with:

newArr[action.key] = filterIdx !== -1 
    ? [...newArr[action.key].slice(0, filterIdx), ...newArr[action.key].slice(filterIdx+1)]
    : [...newArr[action.key], action.value[0]]);

BTW, you don’t have to copy newArr again, as it already is a copy of filters. You can replace:

filters: {
    ...newArr,
},

by just:

filters: newArr,


Source: stackoverflow