State allows components to remember and react to user interactions. React’s useState hook is the foundation of state management.
The useState Hook
Import useState from React and use it to create state variables:
import { useState } from "react";
const [count, setCount] = useState(Number);
useState returns an array with two elements: the current state value and a function to update it.
Complete State Example
Here’s a counter component with state management:
import { useState } from "react";
import cesese from './ItemCounter.module.css';
interface Props {
name: string;
quantity?: number;
}
export const ItemCounter = ({ name, quantity }: Props) => {
const [count, setCount] = useState(Number);
const handleAdd = () => {
setCount(count + 1);
};
const handleSub = () => {
if (count === 0) return;
setCount(count - 1);
};
const handleClick = () => {
console.log(`homero homero homero ${name}`);
};
return (
<section className={cesese['item-row']}>
<span
className="item-text"
style={{
color: count === 0 ? 'red' : 'black',
}}
>
{name}
</span>
<button
onClick={(event) => {
handleAdd();
}}
>
+1
</button>
<span>{count}</span>
<button onClick={handleSub}>-1</button>
</section>
);
};
How State Works
Initialize state
Call useState with an initial value (or type like Number).const [count, setCount] = useState(Number);
Read state
Use the state variable directly in your JSX. Update state
Call the setter function to update the state. React re-renders
When state changes, React automatically re-renders the component with the new value.
Event Handlers
Create handler functions to manage state updates:
const handleAdd = () => {
setCount(count + 1);
};
const handleSub = () => {
if (count === 0) return;
setCount(count - 1);
};
Add validation logic in your handlers (like if (count === 0) return;) to prevent invalid states.
Connecting Events to Handlers
There are two ways to connect event handlers:
Direct Reference
<button onClick={handleSub}>-1</button>
Inline Arrow Function
<button
onClick={(event) => {
handleAdd();
}}
>
+1
</button>
Use inline arrow functions when you need to pass parameters or call multiple functions.
Conditional Styling with State
Use state to dynamically change styles:
<span
className="item-text"
style={{
color: count === 0 ? 'red' : 'black',
}}
>
{name}
</span>
This changes the text color to red when the count reaches zero.
State Best Practices
Never mutate state directly
Always use the setter function. Don’t do: count = count + 1.// ❌ Wrong
count = count + 1;
// ✅ Correct
setCount(count + 1);
Add validation
Prevent invalid state transitions with conditional checks.if (count === 0) return;
setCount(count - 1);
Use meaningful names
Name your state variables and setters descriptively.const [count, setCount] = useState(0);
const [isLoading, setIsLoading] = useState(false);
Keep state minimal
Only store data that changes and can’t be calculated from other state.
Debugging State
Log state values to understand how they change:
const handleClick = () => {
console.log(`homero homero homero ${name}`);
};
Install React Developer Tools browser extension to inspect component state in real-time.
Common State Patterns
Counter Pattern
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
Toggle Pattern
const [isOpen, setIsOpen] = useState(false);
const toggle = () => setIsOpen(!isOpen);
const [text, setText] = useState("");
const handleChange = (e) => setText(e.target.value);