Home > Back-end >  JS spread operator workflow on React
JS spread operator workflow on React

Time:12-07

React suggests not to mutate state. I have an array of objects which I am manipulating based on some events. My question is, is it okay to write it like this:

const makeCopy = (arr) => arr.map((item) => ({ ...item }));

function SomeComponenet() {
    const [filters, setFilters] = useState(aemFilterData);

    const handleFilterClick = (filter, c) => {
        let copiedFilters = makeCopy(filters);

        /**
         * Apply toggle on the parent as well
         */
        if (!("parentId" in filter)) {
            copiedFilters[filter.id].open = !copiedFilters[filter.id].open;
        }
        setFilters(copiedFilters);
    }
}

Am I mutating the original object by doing like above? Or does it make a difference if written like this:

const makeCopy = (arr) => arr.map((item) => ({ ...item }));

function SomeComponent() {
    const [filters, setFilters] = useState(aemFilterData);

    const handleFilterClick = (filter, c) => {
        let copiedFilters = makeCopy(filters);

        /**
         * Apply toggle on the parent as well
         */
        if (!("parentId" in filter)) {
            copiedFilters = copiedFilters.map((f) => {
            if (filter.id === f.id) {
              return {
                ...f,
                open: !f.open,
              };
            } else {
              return { ...f };
            }
          });
        }
        setFilters(copiedFilters);
    }
}

What's the preferred way to do this? Spread operators are getting a lot verbose and I am not liking it, but I prefer it if that's how I need to do it here. immutable.js and immer or not an option right now.

CodePudding user response:

const makeCopy = (arr) => arr.map((item) => item );

With above code, it's mutating on the original object reference because we're not creating a deep clone.

copiedFilters[filter.id].open = !copiedFilters[filter.id].open;

Here reference of copiedFilters[filter.id] and filters[filter.id] is same.

With spread operator

const makeCopy = (arr) => arr.map((item) => ({ ...item }));

Here we create a new copy of the inner object too. So copiedFilters[filter.id] and filters[filter.id] will have different reference.

This is same as your second approach.

So either you use spread operator while making a copy or you can skip making a copy in the second approach and directly map on filters since you're using spread operator there. This looks better because, why run loop twice - first to create copy and then to update open.

// let copiedFilters = makeCopy(filters); Not needed in second approach
copiedFilters = copiedFilters.map((f) => {
  if (filter.id === f.id) {
    return {
      ...f,
      open: !f.open,
    };
  } else {
    return { ...f };
  }
});

You can create a deep clone when you copy but that would be waste of computation and memory, I don't think it's needed here. Deep clone is helpful when you have further nesting in the object.

  • Related