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:
- The current state value.
- 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>
);
}