Why are props immutable in React, and what breaks if they aren’t?

HighIntermediateReact
Preparing for interviews?

Use guided tracks for structured prep, then practice company-specific question sets when you want targeted interview coverage.

Quick Answer

Explain why React treats props as read-only inputs (UI = f(props, state, context)). Connect this to predictable rendering, parent ownership, referential equality optimizations (PureComponent/React.memo), and why mutating props can cause missed updates, shared-state bugs, and inconsistent UI—especially under concurrent rendering and StrictMode.

Answer

Core idea

Props are inputs owned by the parent. React’s mental model is: UI = f(props, state, context). If a child can mutate its inputs, rendering stops being a pure computation and you get hidden side effects and shared mutable state across components.

Why props are read-only

What React assumes

What you gain

Parent owns the data

Only the parent decides when/why props change

Clear ownership + easier reasoning

Render should be pure

Same inputs => same output

Safe re-renders, retries, and dev StrictMode stress tests

Optimizations rely on identity

Shallow comparisons (memo/PureComponent) are meaningful

Skipping work becomes correct and predictable

Immutability is a contract that keeps rendering deterministic and debuggable

What breaks if you mutate props

JavaScript won’t stop you from mutating objects/arrays passed via props, but React will still treat props as if they were immutable. That mismatch causes bugs.

Breakage

What it looks like

Why it happens

Missed re-renders / stale UI

You change a field, but UI doesn’t update (or updates inconsistently)

Parent didn’t produce a new reference; memo/shallow compare thinks “nothing changed”

Shared mutable state bugs

One child “mysteriously” affects another sibling

They both reference the same mutated object/array

Invalid assumptions in concurrent rendering

Weird flickers, order-dependent bugs, “it depends on timing”

React may render, pause, retry; mutations during render leak across attempts

Debugging becomes painful

You can’t trace where the data changed

Mutation hides the real source of change (no single writer)

Mutating props breaks the parent->child contract and React’s optimization model
JSX
import React from 'react';

const UserCard = React.memo(function UserCard({ user }) {
  // ❌ Mutating a prop object
  user.lastSeenAt = Date.now();

  return (
    <div>
      <div>{user.name}</div>
      <div>lastSeenAt: {user.lastSeenAt}</div>
    </div>
  );
});

export default function App() {
  const [user, setUser] = React.useState({ id: 1, name: 'Ada', lastSeenAt: 0 });

  // Parent does NOT create a new object unless setUser is called.
  // UserCard is memoized; shallow compare sees same `user` reference and may skip re-render.
  return (
    <>
      <UserCard user={user} />
      <button onClick={() => setUser((u) => ({ ...u, name: u.name + '!' }))}>
        Update name (new object)
      </button>
    </>
  );
}
                  

Another classic footgun: mutating arrays

Sorting, pushing, splicing, or reversing a prop array mutates in-place and can corrupt parent/sibling views.

JSX
function List({ items }) {
  // ❌ Mutates parent-owned array in-place
  items.sort((a, b) => a.label.localeCompare(b.label));

  return <ul>{items.map((x) => <li key={x.id}>{x.label}</li>)}</ul>;
}

// ✅ Make a copy
function ListSafe({ items }) {
  const sorted = [...items].sort((a, b) => a.label.localeCompare(b.label));
  return <ul>{sorted.map((x) => <li key={x.id}>{x.label}</li>)}</ul>;
}
                  

If you need to “change props”…

Do this instead

Child needs to request an update

Pass a callback prop (events up), parent updates state and passes new props down

Need derived data

Compute immutably (copy + transform) inside render or memoize with useMemo if expensive

Need local editable state

Initialize local state from props carefully (and handle updates explicitly)

Props are inputs; changes flow via state updates and callbacks
Summary

Props are immutable because React’s rendering model assumes components are pure functions of their inputs, and because performance optimizations depend on stable identity + parent ownership. If you mutate props, you introduce hidden side effects: missed updates, cross-component contamination, and timing-sensitive bugs—especially with memoization and concurrent rendering.

Similar questions
Guides
8 / 41