Back to roadmaps react Course

Components and State Management

React applications are built from modular components. Renders update automatically when a component state changes. Let us examine component declarations and the useState hook.


1. Functional vs Class Components

In the early days of React, state management was limited to Class Components. Since React 16.8 (Hooks), Functional Components are the industry standard because they are simpler, cleaner, and offer better performance optimization.

Functional Component (Modern Standard)

import { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

Class Component (Legacy Style)

import React from "react";

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  render() {
    return (
      <button onClick={() => this.setState({ count: this.state.count + 1 })}>
        Count: {this.state.count}
      </button>
    );
  }
}

2. Managing State with the useState Hook

The useState hook declares state variables in functional components. It takes the initial state value as an argument and returns an array with two elements:

  1. The current state value.
  2. A setter function to update the state.
// Destructure current state value and update function
const [state, setState] = useState(initialValue);

State is Immutable

Never mutate state directly (for example, do not assign state = newValue). Doing so will not trigger a component re-render. Always use the setter function to schedule updates.


3. Functional State Updates

If your new state depends on the previous state, pass a callback function to the setter. This ensures you always read the most up-to-date state even during batch updates:

import { useState } from "react";

function Incrementer() {
  const [count, setCount] = useState(0);

  const increaseByThree = () => {
    // Correct way to queue sequential updates
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
  };

  return (
    <button onClick={increaseByThree}>Count: {count}</button>
  );
}

4. Managing Complex State Objects

If you store an object or array in state, you must copy the existing properties using the JavaScript spread operator before updating specific fields:

import { useState } from "react";

function UserForm() {
  const [user, setUser] = useState({ name: "Alice", role: "Developer" });

  const updateName = (newName) => {
    // Merge updates into a new object copy
    setUser(prevUser => ({
      ...prevUser,
      name: newName
    }));
  };

  return (
    <div>
      <p>User: {user.name} ({user.role})</p>
      <button onClick={() => updateName("Charlie")}>Set Charlie</button>
    </div>
  );
}
Published on Last updated: