The Hidden Pitfalls of Mutating Arrays in React Component Props

2023-03-13

#frontend#development
The Hidden Pitfalls of Mutating Arrays in React Component Props

You push one item into an array prop. The component re-renders. Now there are two. Re-render again — three. You stare at the screen, wondering if React is broken.

React is fine. You mutated a prop.

The Bug That Looks Like Magic

You're building a search results component. You want a "Load More" button at the end of the list. Simple enough — just push it onto the results array:

const SearchResults = ({ results }) => {
  results.push({ name: "Load More", type: "button" });

  return (
    <div>
      {results.map((result, index) => (
        <div key={index}>{result.name}</div>
      ))}
    </div>
  );
};

First render looks perfect. Second render — two "Load More" buttons. Third — three. The button multiplies like a virus because you're mutating the original array every time the component renders.

Why This Happens

JavaScript passes arrays by reference. When you call .push() on a prop, you're not modifying a local copy. You're reaching back into the parent's data and changing it permanently.

const myArray = [1, 2, 3];
const mutateArray = (arr) => {
  arr.push(4);
};

mutateArray(myArray);
console.log(myArray); // Output: [1, 2, 3, 4]

The parent doesn't know its data changed. React doesn't detect a state update. But the damage is done — and it compounds on every render.

The Fix Takes One Line

Stop mutating. Create a new array instead:

const SearchResults = ({ results }) => {
  const newResults = [...results, { name: "Load More", type: "button" }];

  return (
    <div>
      {newResults.map((result, index) => (
        <div key={index}>{result.name}</div>
      ))}
    </div>
  );
};

The spread operator creates a fresh array. The original stays untouched. The bug vanishes.

This isn't just a React rule — it's a JavaScript survival skill. Every .push(), .splice(), or direct property assignment on a prop is a mutation waiting to betray you. The spread operator is your defense.

If you're reaching for .push() inside a component, you're not adding data — you're planting a time bomb.