HOWTO · React

How to Update Nested State Properties in React

Learn how React class components update top-level state, copy nested objects immutably, use props as inputs, and calculate state from its previous value.

On this page

For class components, setState() schedules a state update. It accepts an object or an updater function and shallowly merges the returned object into the current top-level state. That merge does not recursively combine nested objects, so updating one nested field requires copying each object along the path. React then renders with the new state. These patterns apply to class components; function components use a different state API.

What setState() updates in a class component

State is an object owned by a class component. Calling this.setState({ greeting: 'Welcome!' }) changes the top-level greeting property while retaining other top-level properties. It does not replace the whole state object. Updates may be batched, so code that depends on a newly committed render should not assume this.state changes immediately after the call.

Update top-level state properties

For one property, pass a partial object such as this.setState({ greeting: 'Welcome!' }). For several, include each top-level property in the same object: this.setState({ test: 'Programming Quiz', questions: 10, students: 30 }). This is useful when the new values are known independently of the previous state. These fields are object properties, not entries in an array.

Update a nested object immutably

Copy the top-level state and every nested object that changes, then pass the copied branch to setState(). The following standalone JavaScript example shows the copy pattern. Its nextState object retains the existing name and alert preference while changing the theme.

Run this example:

const state = {
  profile: {
    name: 'Ada',
    preferences: { theme: 'light', alerts: true }
  },
  status: 'active'
};

const nextState = {
  ...state,
  profile: {
    ...state.profile,
    preferences: {
      ...state.profile.preferences,
      theme: 'dark'
    }
  }
};

console.log(JSON.stringify(nextState));

In a class component, use the functional updater so both copied levels come from the state React supplies for this update: this.setState((prevState) => ({ profile: { ...prevState.profile, preferences: { ...prevState.profile.preferences, theme: 'dark' } } })). Copying prevState.profile preserves sibling profile fields, and copying prevState.profile.preferences preserves sibling preference fields. Mutating either nested object directly changes the existing state and should be avoided.

Use props as inputs to state

Props are inputs supplied by a parent; a child component does not update them with setState(). Read a collection from this.props.testTopics and render it with a list, for example this.props.testTopics.map(topic => <li key={topic}>{topic}</li>). Keep derived display data in render() when it can be computed from props. Copy props into state only when the component intentionally needs an independent value that can later diverge from its initial prop.

Update state from its previous value

When the next value depends on the current count or another state field, use the updater form: this.setState((prevState) => ({ count: prevState.count + 1 })). React supplies the state value for that update, so queued increments build on one another instead of reading a possibly stale this.state. The updater should calculate and return the partial state object; do not mutate prevState.

Choose the right update pattern

Use an object update for new top-level values that do not depend on prior state. Copy every affected level when changing nested data. Treat props as inputs and render their data directly when possible. Use the functional updater when calculating from prior state. These rules keep class-component updates predictable while preserving unrelated state fields.