How to use state in React
Using state is fundamental for creating interactive React components that can store and update data over time, triggering re-renders when values change. As the creator of CoreUI, a widely used open-source UI library, I’ve implemented state management in countless React components for form controls, toggles, modals, and complex interactive elements across enterprise applications. From my expertise, the most effective approach is to use the useState hook with proper state initialization. This method provides simple state management, clear update patterns, and excellent performance while maintaining component isolation and predictable behavior.
Use the useState
hook to manage component state with proper initialization and state update functions.
import { useState } from 'react'
function Counter() {
// State variable with initial value
const [count, setCount] = useState(0)
const [message, setMessage] = useState('')
const increment = () => {
setCount(count + 1)
}
const decrement = () => {
setCount(prevCount => prevCount - 1)
}
const reset = () => {
setCount(0)
setMessage('Counter reset!')
}
return (
<div>
<h2>Count: {count}</h2>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={reset}>Reset</button>
{message && <p>{message}</p>}
</div>
)
}
// Complex state with objects
function UserForm() {
const [user, setUser] = useState({
name: '',
email: '',
age: ''
})
const handleInputChange = (field, value) => {
setUser(prevUser => ({
...prevUser,
[field]: value
}))
}
return (
<form>
<input
type="text"
placeholder="Name"
value={user.name}
onChange={(e) => handleInputChange('name', e.target.value)}
/>
<input
type="email"
placeholder="Email"
value={user.email}
onChange={(e) => handleInputChange('email', e.target.value)}
/>
<input
type="number"
placeholder="Age"
value={user.age}
onChange={(e) => handleInputChange('age', e.target.value)}
/>
<p>User: {JSON.stringify(user, null, 2)}</p>
</form>
)
}
The useState
hook returns an array with the current state value and a setter function. Initialize state by passing the initial value to useState. Update state by calling the setter function with the new value or a function that receives the previous state. When updating objects or arrays, always create new references using spread operator to ensure React detects changes. Use functional updates when the new state depends on the previous state to avoid stale closures.
Best Practice Note:
This is the same approach we use in CoreUI React components for managing component state and user interactions. Initialize state with appropriate default values, use functional updates for state that depends on previous values, keep state as simple as possible, and consider splitting complex state into multiple useState calls for better organization.