Popular Searches
Popular Course Categories
Popular Courses

Updating State

Updating State

State Management with useState

Updating State in React JS

Updating State in React JS means changing the current data stored in a component and displaying the updated information in the user interface. React provides the useState() Hook for managing state in functional components. The setter function returned by useState() is used to request state updates.

Learn more: JustAcademy React JS Training Course | Register for React JS Course Demo


1. What Is State in React?

State is data that a React component remembers between renders. It can store values such as numbers, strings, booleans, arrays, and objects. State is useful when information changes because of user interactions or other application events.

Examples of state include:

  • A counter value that increases or decreases.
  • A username entered into a form.
  • A menu that opens and closes.
  • A list of tasks in a To-Do application.
  • Shopping cart items and quantities.
  • Login status or selected preferences.

2. What Does Updating State Mean?

Updating state means requesting React to store a new value for a state variable. When the new value differs from the current value, React generally renders the component again so the interface can reflect the change.

Example

import { useState } from 'react';
function App() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h2>Count: {count}</h2>
      <button onClick={() => setCount(count + 1)}>
        Increase
      </button>
    </div>
  );
}
export default App;

Explanation:

  • useState(0) initializes the counter to 0.
  • count represents the current state value for that render.
  • setCount() requests a state update.
  • Clicking the button increases the count by one.
  • React renders the updated counter value.

3. Syntax for Updating State

The basic syntax for updating state with useState() is:

const [state, setState] = useState(initialValue);
setState(newValue);
Part Meaning
state The current state value for the render.
setState The setter function used to request an update.
initialValue The starting value used when the component initializes.
newValue The value that React should store as the next state.

For example:

const [name, setName] = useState('Guest');
setName('Rahul');

The next state value will be 'Rahul'. Normally, call the setter in an event handler or other appropriate logic, not unconditionally during rendering.


4. Updating State with Different Data Types

4.1 Updating a Number

Number state is commonly used for counters, scores, quantities, and pagination.

import { useState } from 'react';
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increase
      </button>
      <button onClick={() => setCount(count - 1)}>
        Decrease
      </button>
    </div>
  );
}
export default Counter;

Explanation: The Increase button adds one to the current count, while the Decrease button subtracts one.

4.2 Updating a String

String state is useful for names, messages, search terms, and form fields.

import { useState } from 'react';
function NameComponent() {
  const [name, setName] = useState('Guest');
  return (
    <div>
      <p>Name: {name}</p>
      <button onClick={() => setName('Amit')}>
        Change Name
      </button>
    </div>
  );
}
export default NameComponent;

Initially, the name is Guest. Clicking the button requests an update to Amit.

4.3 Updating a Boolean

Boolean state contains either true or false. It is commonly used to control visibility, menus, checkboxes, and toggles.

import { useState } from 'react';
function ToggleMessage() {
  const [isVisible, setIsVisible] = useState(false);
  return (
    <div>
      <button onClick={() => setIsVisible(!isVisible)}>
        Toggle Message
      </button>
      {isVisible && <p>Welcome to React JS!</p>}
    </div>
  );
}
export default ToggleMessage;

The expression !isVisible reverses the Boolean value. When the value becomes true, the message appears; when false, it disappears.


5. Updating State Using the Previous State

Sometimes, the next state depends on the previous state. In these situations, React recommends using an updater function, especially when multiple updates may be queued before another render.

Syntax

setState(previousState => {
  return nextState;
});

Example: Incrementing a Counter

import { useState } from 'react';
function Counter() {
  const [count, setCount] = useState(0);
  function increaseCount() {
    setCount(previousCount => previousCount + 1);
  }
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increaseCount}>Increase</button>
    </div>
  );
}
export default Counter;

Explanation: React passes the pending state value to the updater function. The function calculates the next value using previousCount + 1.

Why Use an Updater Function?

Consider this code:

function increaseThreeTimes() {
  setCount(count + 1);
  setCount(count + 1);
  setCount(count + 1);
}

All three calls use the same count value from the current render. Therefore, they do not necessarily increase the count by three.

Correct approach:

function increaseThreeTimes() {
  setCount(previousCount => previousCount + 1);
  setCount(previousCount => previousCount + 1);
  setCount(previousCount => previousCount + 1);
}

React processes the updater functions in sequence, so the count increases by three when these updates are processed together.


6. Updating State with Objects

Objects are useful for storing related information, such as a person's name, age, city, and email. When updating an object in state, create a new object rather than modifying the existing state object directly.

Example

import { useState } from 'react';
function UserProfile() {
  const [user, setUser] = useState({
    name: 'Priya',
    age: 22,
    city: 'Mumbai'
  });
  function updateAge() {
    setUser({
      ...user,
      age: 23
    });
  }
  return (
    <div>
      <p>Name: {user.name}</p>
      <p>Age: {user.age}</p>
      <p>City: {user.city}</p>
      <button onClick={updateAge}>Update Age</button>
    </div>
  );
}
export default UserProfile;

Explanation:

  • user stores the object.
  • ...user copies the existing object's properties into a new object.
  • age: 23 replaces the age value.
  • The name and city remain unchanged.

Important: Avoid directly changing state with user.age = 23. Treat state objects as read-only and replace them using the setter.


7. Updating Nested Objects

When state contains nested objects, copy each level from the root object down to the property being updated.

Example

import { useState } from 'react';
function Student() {
  const [student, setStudent] = useState({
    name: 'Riya',
    address: {
      city: 'Mumbai',
      country: 'India'
    }
  });
  function updateCity() {
    setStudent({
      ...student,
      address: {
        ...student.address,
        city: 'Pune'
      }
    });
  }
  return (
    <div>
      <p>Name: {student.name}</p>
      <p>City: {student.address.city}</p>
      <button onClick={updateCity}>Change City</button>
    </div>
  );
}
export default Student;

Here, both the outer student object and its nested address object are copied. This preserves the existing name and country while changing the city.


8. Updating State with Arrays

Arrays in state are useful for task lists, product collections, messages, and shopping carts. Do not directly mutate an array in state. Instead, create a new array and pass it to the setter function.

8.1 Adding an Item

import { useState } from 'react';
function TodoList() {
  const [todos, setTodos] = useState(['Learn HTML', 'Learn CSS']);
  function addTodo() {
    setTodos(previousTodos => [...previousTodos, 'Learn React']);
  }
  return (
    <div>
      <ul>
        {todos.map((todo, index) => (
          <li key={index}>{todo}</li>
        ))}
      </ul>
      <button onClick={addTodo}>Add Todo</button>
    </div>
  );
}
export default TodoList;

The spread operator copies the previous items into a new array and adds the new task at the end.

8.2 Removing an Item

function removeTodo(indexToRemove) {
  setTodos(previousTodos =>
    previousTodos.filter((todo, index) => index !== indexToRemove)
  );
}

The filter() method returns a new array containing the items that meet the condition.

8.3 Updating an Item

function updateTodo(indexToUpdate) {
  setTodos(previousTodos =>
    previousTodos.map((todo, index) =>
      index === indexToUpdate ? 'Updated Task' : todo
    )
  );
}

The map() method creates a new array and replaces only the selected item.

Common Array Methods

Operation Recommended Approach
Add item [...items, newItem]
Remove item filter()
Update item map()
Combine arrays concat() or spread syntax
Sort items Copy the array first, then sort the copy

9. Updating State in Form Inputs

React forms often use state to store the values entered by users. A controlled input receives its current value from state and updates that state through an event handler.

Example: Name Input

import { useState } from 'react';
function NameForm() {
  const [name, setName] = useState('');
  return (
    <div>
      <input
        type="text"
        value={name}
        placeholder="Enter your name"
        onChange={event => setName(event.target.value)}
      />
      <p>Your name: {name}</p>
    </div>
  );
}
export default NameForm;

Explanation: Whenever the user types, onChange receives the event and passes the new input value to setName(). React then displays the updated value.

Example: Updating Multiple Form Fields

import { useState } from 'react';
function RegistrationForm() {
  const [form, setForm] = useState({
    name: '',
    email: ''
  });
  function handleChange(event) {
    const { name, value } = event.target;
    setForm(previousForm => ({
      ...previousForm,
      [name]: value
    }));
  }
  return (
    <div>
      <input
        name="name"
        value={form.name}
        placeholder="Enter name"
        onChange={handleChange}
      />
      <input
        name="email"
        value={form.email}
        placeholder="Enter email"
        onChange={handleChange}
      />
      <p>Name: {form.name}</p>
      <p>Email: {form.email}</p>
    </div>
  );
}
export default RegistrationForm;

The computed property [name] updates the field identified by the input's name attribute while preserving the other form values.


10. Updating State with Toggle Buttons

A toggle button switches a Boolean state between true and false. The functional updater form is useful because the next value depends on the previous value.

import { useState } from 'react';
function ThemeToggle() {
  const [isDark, setIsDark] = useState(false);
  return (
    <div>
      <p>Current theme: {isDark ? 'Dark' : 'Light'}</p>
      <button onClick={() => setIsDark(previous => !previous)}>
        Switch Theme
      </button>
    </div>
  );
}
export default ThemeToggle;

Each click reverses the current Boolean value, switching between Light and Dark.


11. Updating State Is Not Immediately Synchronous

Calling a state setter requests an update. It does not change the state variable in the currently executing render or event handler.

function handleClick() {
  setCount(count + 1);
  console.log(count);
}

The console.log(count) statement uses the value from the current render, so it may log the previous value.

To observe the updated value after React renders, you can use an Effect when appropriate:

import { useEffect, useState } from 'react';
function Counter() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log('Updated count:', count);
  }, [count]);
  return (
    <button onClick={() => setCount(previous => previous + 1)}>
      Count: {count}
    </button>
  );
}
export default Counter;

The Effect runs after a render in which the dependency count has changed. Effects should be used for synchronizing with external systems, not simply for calculating values that can be derived during rendering.


12. Updating State vs Mutating State

Updating state correctly means creating or supplying the next value through the setter. Mutating state means directly changing an existing object or array stored in state.

Incorrect Mutation Correct Update
user.name = 'Neha'; setUser({ ...user, name: 'Neha' });
items.push('React'); setItems(previous => [...previous, 'React']);
items.splice(0, 1); setItems(previous => previous.filter((item, index) => index !== 0));
user.age = 25; setUser({ ...user, age: 25 });

Direct mutation can prevent React from detecting the intended change and can also alter data associated with previous renders. Treat state as read-only and create new objects or arrays for updates.


13. Common Mistakes When Updating State

Mistake 1: Calling the setter during rendering without a condition

// Incorrect: can cause repeated renders
function Counter() {
  const [count, setCount] = useState(0);
  setCount(count + 1);
  return <p>{count}</p>;
}

Correct: Update state in response to an event or through other appropriate logic.

<button onClick={() => setCount(previous => previous + 1)}>
  Increase
</button>

Mistake 2: Mutating an array directly

// Incorrect
items.push('JavaScript');
setItems(items);

Correct:

setItems(previousItems => [...previousItems, 'JavaScript']);

Mistake 3: Updating an object without preserving other fields

// May discard other properties
setUser({ age: 25 });

Correct when updating only the age:

setUser(previousUser => ({
  ...previousUser,
  age: 25
}));

Mistake 4: Expecting the state variable to change immediately

After calling the setter, the state variable in the current render still represents its existing value. React supplies the next state during a subsequent render.

Mistake 5: Using a stale value for consecutive updates

When the next value depends on the previous state, prefer an updater function such as setCount(previous => previous + 1).


14. Best Practices for Updating State

  • Use the setter returned by useState() to request state updates.
  • Use functional updater functions when the next value depends on the previous value.
  • Never directly mutate objects or arrays stored in state.
  • Use the spread operator to preserve existing object properties.
  • Use map() to update array items and filter() to remove them.
  • Keep state minimal and avoid storing values that can be calculated from existing state.
  • Keep updater functions pure and free from side effects.
  • Use stable, unique keys when rendering lists of items.
  • Keep state update logic clear and easy to test.
  • Remember that React may batch state updates and render after the event handler finishes.

15. Practical Project: To-Do List

This simple project demonstrates adding and removing tasks using React state.

import { useState } from 'react';
function TodoApp() {
  const [task, setTask] = useState('');
  const [tasks, setTasks] = useState([]);
  function addTask() {
    const trimmedTask = task.trim();
    if (trimmedTask === '') return;
    setTasks(previousTasks => [
      ...previousTasks,
      { id: Date.now(), text: trimmedTask }
    ]);
    setTask('');
  }
  function removeTask(id) {
    setTasks(previousTasks =>
      previousTasks.filter(item => item.id !== id)
    );
  }
  return (
    <div>
      <h2>My To-Do List</h2>
      <input
        value={task}
        placeholder="Enter a task"
        onChange={event => setTask(event.target.value)}
      />
      <button onClick={addTask}>Add Task</button>
      <ul>
        {tasks.map(item => (
          <li key={item.id}>
            {item.text}
            <button onClick={() => removeTask(item.id)}>
              Remove
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}
export default TodoApp;

Project Explanation

  • task stores the text entered into the input field.
  • tasks stores the list of task objects.
  • setTask() updates the input value as the user types.
  • setTasks() adds a task by creating a new array.
  • filter() removes a task by creating a new array without that task.
  • The key prop helps React identify each task in the rendered list.

16. Interview Questions and Answers

Q1. What is updating state in React?

Updating state means requesting a new state value using the setter function provided by a Hook such as useState().

Q2. Which function updates state created with useState()?

The setter function returned by useState(), such as setCount() or setName().

Q3. What is a functional state update?

It passes a function to the setter. React supplies the pending state to the function, which returns the next state.

setCount(previousCount => previousCount + 1);

Q4. Why should state not be mutated directly?

Direct mutation can prevent React from detecting the intended update and can change data associated with previous renders. Create a new value instead.

Q5. How do you update an object in state?

Use the spread operator to copy the previous object and replace the property that needs to change.

setUser(previousUser => ({
  ...previousUser,
  name: 'Neha'
}));

Q6. How do you add an item to an array in state?

Create a new array using spread syntax or a method such as concat().

setItems(previousItems => [...previousItems, newItem]);

Q7. Does calling a setter immediately change the current state variable?

No. The variable in the currently running render retains its existing value. React processes the update and provides the next value in a subsequent render.

Q8. Why use an updater function for counters?

It calculates the next value from the pending state and helps ensure consecutive queued updates build on one another.

Q9. How can you remove an item from an array in state?

Use filter() to create a new array excluding the item.

Q10. What does the spread operator do when updating an object?

It copies an object's enumerable own properties into a new object. The properties you specify afterward can replace copied values. The copy is shallow, so nested objects must be copied separately when updating them.


17. Practice Exercises

  1. Create a counter with Increase, Decrease, and Reset buttons.
  2. Update a username when the user clicks a button.
  3. Create a show/hide message using Boolean state.
  4. Build a task list that supports adding and removing items.
  5. Create a student object and update the student's city without changing the other fields.
  6. Build a form with name and email fields using a single state object.
  7. Write a function that increases a counter by three using functional state updates.
  8. Create a product list where each product's quantity can be increased independently.

18. Quick Revision Checklist

  • Understand the purpose of state and its setter function.
  • Know how to update numbers, strings, and booleans.
  • Use functional updater functions when appropriate.
  • Update objects by creating new objects.
  • Update arrays with non-mutating approaches.
  • Understand why state setters do not immediately change the current render's variable.
  • Avoid direct mutation and unconditionally setting state during rendering.
  • Practice form handling and list updates.

19. Useful Resources


20. Conclusion

Updating state is a fundamental concept in React JS because it allows components to respond to user interactions and changing data. Use the setter returned by useState() to request updates, use functional updater functions when the next value depends on the previous value, and create new objects or arrays instead of mutating existing state. These practices help make React applications predictable, maintainable, and easier to debug.

To learn more, visit JustAcademy React JS Training Course or register for a React JS course demo.

whatsapp