Skip to main content
Week 05 • Track 01 • The Theory

State of
Mind.

Your app has a short-term memory. It remembers things while the page is open—and forgets everything the moment you refresh. That's state.

0
useState

Click + a few times, then refresh.

The Mental Model

Your browser has a whiteboard.

Every time a user visits your app, the browser opens a blank whiteboard. State is what you write on it. When the user refreshes or closes the tab, the whiteboard gets erased.

useState = A Sticky Note

A value that React watches. When it changes, the screen re-renders.

useEffect = An Alarm Clock

Code that runs at specific moments: on load, on change, on cleanup.

Props = Passing Notes

Data flowing from parent to child. One-way. Read-only to the receiver.

Refresh = Erase the Board

State only lives in memory. Refresh kills it unless you persist it.

Browser Memory
Sticky Note #1
count = 0
Sticky Note #2
isLoggedIn = true
Sticky Note #3
darkMode = false
Refresh → All notes erased

useState

📌

How It Works

useState creates a variable that React watches. When you call the setter function, React re-renders the component with the new value.

component.tsx

const [count, setCount] = useState(0);

// count = the value

// setCount = the updater

// 0 = the initial value

setCount(count + 1);

// React re-renders the component

📐

The Rules of State

1

Never modify state directly

count = 5 is wrong. Always use the setter: setCount(5)

2

State updates are asynchronous

Calling setCount(1) doesn't change count immediately. It schedules a re-render.

3

Each component has its own state

Two copies of the same component don't share state. Each has its own sticky note.

useEffect

Run code at the right moment.

useEffect lets you run code after React renders. It's how you fetch data, set up listeners, or start timers.

Think of it as setting an alarm: "When this component appears, do this thing." And optionally: "When it disappears, clean up."

1
useEffect(() => {...}, [])

Runs once on mount (page load)

2
useEffect(() => {...}, [count])

Runs every time count changes

3
return () => {...}

Cleanup: runs when component unmounts

useEffect-example.tsx

useEffect(() => {

// This runs AFTER render

const timer = setInterval(() => {

setCount(c => c + 1);

}, 1000);

// Cleanup: stop the timer

return () => clearInterval(timer);

}, []); // ← empty = run once

Server vs Screen

Not all data is the same. The trick is knowing where each type lives.

Server Data

Lives in the database. Survives refreshes. Shared across all users.

User profiles
Blog posts
Order history
Settings & preferences

Screen State

Lives in the browser. Dies on refresh. Only for this user, this tab.

Is the modal open?
Which tab is active?
Form input values
Loading spinners

The Persistence Spectrum

useState
Dies on refresh
LocalStorage
Survives refresh
Database
Survives everything

Common Patterns

State Traps

"I'll just use a global variable"

React won't know it changed. No re-render. Use useState.

"I set state but it didn't change"

State updates are batched and async. The new value appears on the next render.

"My useEffect runs twice"

React Strict Mode runs effects twice in dev. It's intentional. Your production code runs once.

"Infinite re-render loop"

Setting state inside useEffect without a dependency array = infinite loop. Always add deps.

Clean State

Keep state close to where it's used

If only one component needs it, put the state there. Don't lift it unless you have to.

Derive values instead of storing them

If you can calculate it from existing state, don't create new state. const total = items.length

Use the function form for updates

setCount(c => c + 1) is safer than setCount(count + 1) in async code.

Always clean up effects

Return a cleanup function from useEffect. Stop timers, remove listeners, cancel requests.

The Exercises

Make your app remember things.

01

The Counter

useState Basics

  • Create a counter with + and - buttons
  • Display the count value
  • Add a reset button
Goal: State changes trigger re-renders
02

The Toggle

Conditional Rendering

  • Create a dark mode toggle
  • Switch background/text colors on click
  • Observe: it resets on refresh
Goal: Boolean state drives UI changes
03

The Timer

useEffect + Cleanup

  • Build a stopwatch with useEffect
  • Add start/stop/reset controls
  • Return a cleanup function
Goal: Side effects with proper cleanup

📋 Quick Reference Cheatsheet

State

const [x, setX] = useState(0)

Effect (on mount)

useEffect(() => { }, [])

Cleanup

return () => clearInterval(id)