Lesson 3 • Beginner
State and Lifecycle ⚛️
Make your components dynamic! Learn useState for managing changing data and useEffect for handling side effects like data fetching and subscriptions.
What You'll Learn in This Lesson
- • The
useStatehook for managing component data - • Updating state with objects and arrays (immutably)
- • The
useEffecthook for side effects - • Dependency arrays and cleanup functions
- • Building a practical todo list with state
npm create vite@latest.1️⃣ useState — The Basics
useState is a React Hook that lets you add state to function components. It returns a pair: the current value and a function to update it. When you call the setter function, React re-renders the component with the new value.
Try It: useState Basics
Learn how state works and how to update it correctly
// useState — Making Components Dynamic
console.log("=== What is State? ===");
console.log("State is data that can CHANGE over time.");
console.log("When state changes, React RE-RENDERS the component.");
console.log();
// Simulating useState
console.log("=== useState Hook ===");
console.log("import { useState } from 'react';");
console.log();
console.log("function Counter() {");
console.log(" const [count, setCount] = useState(0);");
console.log(" // count = current value");
console.log(" //
...2️⃣ Complex State — Objects & Arrays
State can hold any JavaScript value — strings, numbers, booleans, objects, or arrays. When updating objects or arrays, always create a new copy using the spread operator. Never mutate state directly!
Try It: Objects & Arrays
Manage complex state with objects and arrays
// Multiple State Variables
console.log("=== Multiple useState Calls ===");
console.log();
let name = "";
let email = "";
let age = 0;
let isSubscribed = false;
console.log("function SignUpForm() {");
console.log(" const [name, setName] = useState('');");
console.log(" const [email, setEmail] = useState('');");
console.log(" const [age, setAge] = useState(0);");
console.log(" const [isSubscribed, setIsSubscribed] = useState(false);");
console.log("}");
console.log();
// State with objects
...3️⃣ useEffect — Side Effects & Lifecycle
useEffect lets you perform side effects — things that happen outside of rendering, like fetching data, setting up timers, or subscribing to events. The dependency array controls when the effect runs.
Try It: useEffect
Understand the component lifecycle and side effects
// Component Lifecycle with useEffect
console.log("=== useEffect — Side Effects ===");
console.log("useEffect runs code AFTER the component renders.");
console.log();
console.log("// Run on EVERY render:");
console.log("useEffect(() => {");
console.log(" console.log('Component rendered');");
console.log("});");
console.log();
console.log("// Run ONCE on mount:");
console.log("useEffect(() => {");
console.log(" console.log('Component mounted');");
console.log(" // Fetch data, set up subscrip
...4️⃣ Practical Example: Todo List
Let's combine everything into a practical example. This todo list demonstrates adding, toggling, and removing items — all using immutable state updates.
Try It: Todo List
Build a complete todo list with state management
// Practical Example: Todo List State Management
console.log("=== Building a Todo List ===");
console.log();
let todos = [];
let nextId = 1;
function addTodo(text) {
todos = [...todos, { id: nextId++, text, completed: false }];
}
function toggleTodo(id) {
todos = todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
);
}
function removeTodo(id) {
todos = todos.filter(todo => todo.id !== id);
}
// Simulate user actions
addTodo("Learn useState");
addTod
...⚠️ Common Mistakes
state.push(item) won't trigger a re-render. Use setState([...state, item]).setState(prev => prev + 1) (functional update) when the new state depends on the previous state. This avoids stale closure bugs.📋 Quick Reference
| Pattern | Syntax |
|---|---|
| useState | const [val, setVal] = useState(initial) |
| Functional update | setCount(prev => prev + 1) |
| Update object | setObj({ ...obj, key: newVal }) |
| useEffect (mount) | useEffect(() => {}, []) |
| Cleanup | return () => clearInterval(id) |
🎉 Lesson Complete!
You now understand how to make components dynamic with state and handle side effects. Next, we'll learn how to handle user events!
Sign up for free to track which lessons you've completed and get learning reminders.