So far, your React components have been static - they display the same thing every time they render. But real applications need to be interactive: buttons should respond to clicks, forms should remember user input, counters should increment. This is where state comes in. State is data that can change over time, and when it changes, React automatically updates your UI. In this lesson, you'll learn what state is, why it's essential, and how it makes your components come alive.
The Problem: Static Components
Let's try to build a simple counter that doesn't work:
function Counter() {
let count = 0 // Regular variable
const increment = () => {
count = count + 1
console.log(count) // This logs the new value
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
)
}
// Problem: When you click the button:
// - count DOES increase (you can see it in console)
// - But the UI doesn't update!
// - It stays stuck at 0Why doesn't this work? The variable count does increase, but React doesn't know it changed. React only re-renders components when state changes, not when regular variables change.
Key Insight:
Regular JavaScript variables don't trigger re-renders. When you change a variable, React doesn't know about it, so the UI stays the same. You need state to tell React "Hey, something changed - update the UI!"
What is State?
State is data that:
- Belongs to a component - Each component can have its own state
- Can change over time - Unlike props, which are read-only
- Triggers re-renders - When state changes, React updates the UI
- Persists between renders - State values are remembered
- Is local and private - Other components can't see or modify it
Think of state like memory:
• Props are like arguments passed to a function - they come from outside and can't be changed
• State is like variables inside a function - they're created and controlled by the component itself
Real-World State Examples
1. User Interface State
- Is a modal open or closed?
- Which tab is currently selected?
- Is the menu expanded or collapsed?
- Is dark mode enabled?
2. Form State
- What text is in the input field?
- Which checkboxes are checked?
- What option is selected in the dropdown?
- Are there any validation errors?
3. Data State
- List of items in a shopping cart
- Current user information
- Messages in a chat
- Search results
4. Loading and Error State
- Is data currently loading?
- Did an error occur?
- What's the error message?
- Is the operation complete?
State vs Props
It's important to understand the difference between state and props:
// Props - passed from parent, read-only
function Greeting({ name }) {
// name is a prop - you can read it but not change it
// name = "New Name" // ❌ Error! Props are read-only
return <h1>Hello, {name}!</h1>
}
<Greeting name="Alice" /> // Parent controls the name
// State - owned by component, can be changed
function Counter() {
// count is state - the component can change it
const [count, setCount] = React.useState(0)
const increment = () => {
setCount(count + 1) // ✅ Component controls its own state
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
)
}Key Differences
Props:
- Passed from parent component
- Read-only (immutable)
- Controlled by the parent
- Like function parameters
State:
- Created inside the component
- Can be changed (mutable)
- Controlled by the component itself
- Like local variables that trigger re-renders
How State Works
Here's what happens when you use state in React:
- Component renders - React calls your component function
- State is initialized - State starts with its initial value
- User interacts - User clicks a button, types text, etc.
- State updates - You call the state setter function
- React re-renders - React calls your component function again
- UI updates - React updates the DOM with new values
function Counter() {
console.log('Component rendering...')
// Step 1 & 2: Component renders, state initializes to 0
const [count, setCount] = React.useState(0)
const increment = () => {
// Step 3 & 4: User clicks, state updates
setCount(count + 1)
// Step 5 & 6: React re-renders, UI updates
}
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
)
}
// Flow:
// 1. Initial render → count = 0
// 2. User clicks button
// 3. setCount(1) is called
// 4. React re-renders component
// 5. count = 1
// 6. UI shows "Count: 1"State Preview: useState Hook
We'll dive deep into useState in the next lesson, but here's a quick preview of how you create state:
function Example() {
// Create state with useState
const [value, setValue] = React.useState(initialValue)
// ↑ ↑ ↑
// current setter starting value
// value function
// Examples:
const [count, setCount] = React.useState(0)
const [name, setName] = React.useState('')
const [isOpen, setIsOpen] = React.useState(false)
const [items, setItems] = React.useState([])
return <div>...</div>
}The useState hook returns an array with two values:
- The current state value (e.g.,
count) - A function to update it (e.g.,
setCount)
💡 Array Destructuring
const [count, setCount] = React.useState(0)
This uses JavaScript array destructuring. It's equivalent to:const state = React.useState(0)const count = state[0]const setCount = state[1]
When to Use State
✅ Use State For:
- Data that changes over time
- User input and form data
- UI state (modals, tabs, menus)
- Fetched data from APIs
- Toggle states (on/off, open/closed)
- Counters, timers, and animations
- Shopping cart items
- Selected items or options
❌ Don't Use State For:
- Data that never changes (use constants)
- Data from props (props are already reactive)
- Computed values (calculate from existing state)
- Values that don't affect rendering
function Example() {
// ✅ Good - needs to change and affect UI
const [count, setCount] = React.useState(0)
const [username, setUsername] = React.useState('')
const [isLoading, setIsLoading] = React.useState(false)
// ❌ Bad - never changes, use const
const [appName, setAppName] = React.useState('My App')
// ✅ Better
const appName = 'My App'
// ❌ Bad - computed from state, don't duplicate
const [count, setCount] = React.useState(0)
const [doubleCount, setDoubleCount] = React.useState(0)
// ✅ Better - just calculate it
const [count, setCount] = React.useState(0)
const doubleCount = count * 2
// ❌ Bad - comes from props
const [userProp, setUserProp] = React.useState(props.user)
// ✅ Better - just use props directly
const { user } = props
return <div>...</div>
}Core State Principles
1. State is Isolated and Private
Each component instance has its own state. If you render the same component twice, each has independent state:
function Counter() {
const [count, setCount] = React.useState(0)
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}
function App() {
return (
<div>
<Counter /> {/* Has its own count */}
<Counter /> {/* Has its own separate count */}
</div>
)
}
// Clicking button in first Counter doesn't affect second Counter!2. State Updates are Asynchronous
function Counter() {
const [count, setCount] = React.useState(0)
const handleClick = () => {
setCount(count + 1)
console.log(count) // Still shows OLD value!
// State update happens later
}
return (
<button onClick={handleClick}>
Count: {count}
</button>
)
}
// When you click:
// 1. setCount(1) is called
// 2. console.log(count) runs → shows 0 (old value)
// 3. Later, React re-renders with count = 13. State is Immutable
You should never modify state directly. Always use the setter function:
function Example() {
const [count, setCount] = React.useState(0)
const [user, setUser] = React.useState({ name: 'Alice' })
// ❌ Never do this - mutating state directly
count = count + 1
user.name = 'Bob'
// ✅ Always use setter function
setCount(count + 1)
setUser({ ...user, name: 'Bob' })
}Interactive Demo
💡 Tip: Edit the code above and click "Run" to see your changes
Building a Mental Model
To really understand state, here's a helpful mental model:
Think of React Components Like Functions
// Regular function
function add(a, b) {
return a + b
}
add(2, 3) // Returns 5
add(2, 3) // Returns 5 again - same inputs, same output
// React component without state - like a pure function
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>
}
<Greeting name="Alice" /> // Always renders "Hello, Alice!"
<Greeting name="Alice" /> // Same input, same output
// React component with state - has "memory"
function Counter() {
const [count, setCount] = React.useState(0) // Memory!
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
)
}
// First render: shows 0
// After click: shows 1 (remembers the click!)
// After another click: shows 2 (remembers both clicks!)State is Like a Snapshot
Each render is like a photograph of your component at a moment in time. The state values in that render won't change - they're frozen in that snapshot.
function Counter() {
const [count, setCount] = React.useState(0)
const handleClick = () => {
// In THIS render, count is 0
setCount(count + 1) // Schedule next render with count = 1
setCount(count + 1) // Still using count = 0!
setCount(count + 1) // Still count = 0!
// All three use count = 0, so next render shows 1, not 3!
}
return <button onClick={handleClick}>{count}</button>
}
// This is because count doesn't change during a render
// It's locked to the value it had when the render startedKey Takeaways
- State is data that can change over time within a component
- Regular variables don't trigger re-renders, state does
- Props come from parent (read-only), state is owned by component (changeable)
- When state changes, React re-renders the component
- Each component instance has its own isolated state
- State updates are asynchronous - they happen later
- Never modify state directly - always use the setter function
- State is like memory that persists between renders
- Each render is a snapshot with fixed state values
- Use state for data that changes and affects the UI
- Don't use state for constants or computed values
- State makes components interactive and dynamic
What's Next?
You now understand what state is and why it's essential. But you still need to learn how to actually use it!
In the next lesson, you'll learn the useState hook - React's way of adding state to your components. You'll learn:
- How to create state variables
- How to update state and trigger re-renders
- How to handle different types of state (strings, numbers, booleans, objects, arrays)
- How to make your components truly interactive
Get ready to bring your components to life with the useState hook! 🎯