ProgramGuru

Updating Arrays in State

Updating Arrays in State

A class roster needs to add a student, remove a record or correct a mark. These operations affect a collection, but the existing state array and the existing records still need to remain unchanged.

Create a new array for each state update. Spread can append an item, filter can remove matching items and map can replace one item while preserving the others. Copy an edited object as well as the surrounding array.

  1. Explain

    Add a student using a new array instead of mutating state.

  2. Trace

    Correct one record with map while preserving the other records.

  3. Apply

    Use stable IDs to identify which student the update concerns.

Array Updates: follow the relationship

  1. Existing student list

    The current state array contains the school’s records.

  2. Create a new array

    Spread adds a record; map replaces only the matching record.

  3. Render updated rows

    React receives the new array and matches rows by stable student IDs.

Read this relationship alongside the complete code. This diagram explains the flow; it does not execute React.

Build the mental model

Start with the operation’s meaning: add, remove or replace. Appending uses [...previous, newStudent]; removal keeps records whose IDs do not match; replacement maps every record and returns a new object only for the matching student. Identity and update logic both use stable IDs.

Collections have two levels of identity

The array is one state value, and each record inside it is another object. A new array does not automatically create new records. When correcting a mark, copy the changed student record as well. When removing a student with filter, retained records need no copy because they are not changed.

Choose a new ID when creating a new record, then retain it for the record’s lifetime. Deriving identity from the name or position can fail after edits and reordering. A production school system must coordinate IDs and persisted updates with its data source; local examples only demonstrate interface state.

Read the complete React example

The example starts with Asha and appends Ravi when clicked. Its button disables after Ravi has been added so this tiny example does not create duplicate IDs. The practice changes Asha’s mark using map and leaves Ravi’s record unchanged.

React · JavaScript with JSX

import React, { useState } from 'react';
export default function App() {
  const [students, setStudents] = useState([{ id: 's1', name: 'Asha' }]);
  const added = students.some(student => student.id === 's2');
  return <main><h1>Class roster</h1><ul>{students.map(student => <li key={student.id}>{student.name}</li>)}</ul><button disabled={added} onClick={() => setStudents(previous => [...previous, { id: 's2', name: 'Ravi' }])}>Add Ravi</button></main>;
}

Expected screen and behavior

Initial screen: Class roster Asha Add Ravi
After selecting Add Ravi: the screen includes Asha Ravi.

Connect the source to the screen

React · main example

import React, { useState } from 'react';
export default function App() {
  const [students, setStudents] = useState([{ id: 's1', name: 'Asha' }]);
  const added = students.some(student => student.id === 's2');
  return <main><h1>Class roster</h1><ul>{students.map(student => <li key={student.id}>{student.name}</li>)}</ul><button disabled={added} onClick={() => setStudents(previous => [...previous, { id: 's2', name: 'Ravi' }])}>Add Ravi</button></main>;
}

A new outer array lets React receive a different state value. The nested record copy preserves the old student snapshot. Returning unchanged objects for unaffected students is safe because those records are not mutated; copying everything is unnecessary for this operation.

Avoid the common mistakes

push, pop, splice and sort mutate their array. Prefer non-mutating alternatives for state, or copy before using a mutating operation. Object spread on an array creates an object with numeric properties rather than an array, so choose square brackets for array copying.

Practice before reading the solution

React · starting example

import React, { useState } from 'react';
export default function App() {
  const [students, setStudents] = useState([{ id: 's1', name: 'Asha' }]);
  const added = students.some(student => student.id === 's2');
  return <main><h1>Class roster</h1><ul>{students.map(student => <li key={student.id}>{student.name}</li>)}</ul><button disabled={added} onClick={() => setStudents(previous => [...previous, { id: 's2', name: 'Ravi' }])}>Add Ravi</button></main>;
}

Correct Asha’s mark in a two-student roster without losing Ravi.

Predict the initial visible text and explain which values determine it. Then inspect the worked solution below. Change one relevant input in your local project and check whether the screen follows your prediction. A working screen should be checked for the intended meaning, not merely the absence of an error.

Worked practice solution

The solution compares IDs rather than names, since names may repeat or change. Its map returns exactly one element for each original element, so the roster length stays two. Only Asha receives a replacement record with the new mark.

React · JavaScript with JSX

import React, { useState } from 'react';
export default function App() {
  const [students, setStudents] = useState([{ id: 's1', name: 'Asha', marks: 40 }, { id: 's2', name: 'Ravi', marks: 35 }]);
  function correct() {
    setStudents(previous => previous.map(student => student.id === 's1' ? { ...student, marks: 45 } : student));
  }
  return <main><ul>{students.map(student => <li key={student.id}>{student.name}: {student.marks}</li>)}</ul><button onClick={correct}>Correct Asha</button></main>;
}

Expected screen and behavior

Initial screen: Asha: 40 Ravi: 35 Correct Asha
After selecting Correct Asha: the screen includes Asha: 45.

Check your reasoning

Choose the explanation that matches React and JavaScript behavior. Review the reasoning for each alternative before moving on.

Which operation removes student s2 without mutating the state array?
Choose one answer. You can try again.

Answer and explanation

students.filter(student => student.id !== 's2')

Correct. It constructs an array containing the remaining records.

Use the idea in the next lesson

Create a new array for each state update. Spread can append an item, filter can remove matching items and map can replace one item while preserving the others. Copy an edited object as well as the surrounding array.

Continue with What Is React?. Revisit Updating Objects in State when the relationship between inputs and the resulting screen needs another look.

Read the primary reference: React documentation on Updating Arrays in State.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Lifting State Up →