๐ญ React State Patterns: The Family Communication Guide
Imagine your React app is a family living in a house. Each room (component) has its own stuff, but sometimes family members need to share things. Letโs learn the five golden rules of family sharing!
๐ The Big Picture
Think of your React app like a family house:
- Each room is a component
- Each room has its own stuff (local state)
- Sometimes rooms need to share things
- The family needs rules so everyone knows where things are
Today we learn 5 patterns to keep the family happy:
- Lifting State Up โ Move shared stuff to a common room
- Derived State โ Calculate things instead of storing copies
- Choosing State Structure โ Organize your toy box smartly
- Preserving State โ Keep things safe when moving around
- Resetting State โ Start fresh with a clean room
1๏ธโฃ Lifting State Up
The Problem: Two Kids Fighting Over the TV Remote
Imagine two kids in different rooms. Both want to control the same TV. If each kid has their own remote with different settings, chaos happens!
The Solution: Put the remote in the living room (parent), and let both kids ask the parent to change channels.
Before (Broken)
// Kid 1 has their own channel
function Kid1() {
const [channel, setChannel] =
useState(1);
return <button>Channel: {channel}</button>;
}
// Kid 2 has their own channel
function Kid2() {
const [channel, setChannel] =
useState(5);
return <button>Channel: {channel}</button>;
}
// ๐ฑ They show different channels!
After (Fixed!)
// Parent holds the ONE remote
function LivingRoom() {
const [channel, setChannel] =
useState(1);
return (
<>
<Kid1
channel={channel}
onChange={setChannel}
/>
<Kid2
channel={channel}
onChange={setChannel}
/>
</>
);
}
// Kids just ask to change
function Kid1({ channel, onChange }) {
return (
<button onClick={() => onChange(2)}>
Channel: {channel}
</button>
);
}
๐ฏ The Golden Rule
When two components need the same data, move it to their closest common parent.
graph TD A[Parent: Owns the State] --> B[Child 1: Uses State] A --> C[Child 2: Uses State] B -.-> A C -.-> A style A fill:#4CAF50,color:#fff style B fill:#2196F3,color:#fff style C fill:#2196F3,color:#fff
2๏ธโฃ Derived State
The Problem: Writing the Same Thing Twice
Imagine you have a shopping list. You write:
- Apples: 3
- Bananas: 2
- Total items: 5
But wait! Do you NEED to write the total? You can always count it!
โ Bad: Storing What You Can Calculate
function Cart() {
const [items, setItems] = useState([
{ name: 'Apple', qty: 3 },
{ name: 'Banana', qty: 2 }
]);
// ๐ฑ Storing total separately
const [total, setTotal] = useState(5);
// Now you must update BOTH!
// Easy to forget and cause bugs!
}
โ Good: Calculate on the Fly
function Cart() {
const [items, setItems] = useState([
{ name: 'Apple', qty: 3 },
{ name: 'Banana', qty: 2 }
]);
// โจ Calculate when needed
const total = items.reduce(
(sum, item) => sum + item.qty,
0
);
// total is always correct!
return <p>Total: {total}</p>;
}
๐ฏ The Golden Rule
If you can calculate something from existing state, donโt store it. Derive it!
| Store This โ | Derive This โจ |
|---|---|
| List of items | Total count |
| Birth date | Age |
| First + Last name | Full name |
| Selected IDs | Selected items |
3๏ธโฃ Choosing State Structure
The Problem: Messy Toy Box
Imagine a toy box where:
- Cars are mixed with dolls
- Some toys have duplicate names
- You canโt find anything!
Good structure = Easy to find things!
5 Rules for a Tidy State
Rule 1: Group Related Data
// โ Scattered
const [x, setX] = useState(0);
const [y, setY] = useState(0);
// โ
Grouped
const [position, setPosition] = useState({
x: 0,
y: 0
});
Rule 2: No Contradictions
// โ Can be both sending AND sent (impossible!)
const [isSending, setIsSending] = useState(false);
const [isSent, setIsSent] = useState(false);
// โ
One status, clear states
const [status, setStatus] = useState('typing');
// 'typing' | 'sending' | 'sent'
Rule 3: No Duplicates
// โ Same data in two places
const [items, setItems] = useState([...]);
const [selectedItem, setSelectedItem] =
useState(items[0]); // Duplicate!
// โ
Store just the ID
const [items, setItems] = useState([...]);
const [selectedId, setSelectedId] =
useState(0);
// Derive the item when needed
const selectedItem = items.find(
i => i.id === selectedId
);
Rule 4: No Deep Nesting
// โ Deep and confusing
const [data, setData] = useState({
user: {
profile: {
settings: {
theme: 'dark'
}
}
}
});
// โ
Flat and simple
const [theme, setTheme] = useState('dark');
const [userId, setUserId] = useState(1);
Rule 5: Avoid Redundancy
// โ firstName + lastName + fullName
// fullName is redundant!
// โ
Just store what you need
const [firstName, setFirstName] =
useState('');
const [lastName, setLastName] =
useState('');
// Derive fullName
const fullName = `${firstName} ${lastName}`;
4๏ธโฃ Preserving State
The Problem: Moving Rooms and Losing Your Toys
When you move to a different room, do your toys disappear? No! They stay where you put them.
In React, components can keep or lose their state based on where they are in the tree.
Same Position = Same State
function App() {
const [isRed, setIsRed] = useState(true);
return (
<div>
{isRed ? (
<Counter style="red" />
) : (
<Counter style="blue" />
)}
{/* Same position = state preserved! */}
</div>
);
}
The counter keeps its count! Why? Because <Counter> is in the same position in the tree, even though the color changes.
graph TD A[App] --> B[div] B --> C["Counter #40;same spot!#41;"] style C fill:#4CAF50,color:#fff
Different Position = Different State
function App() {
const [isRed, setIsRed] = useState(true);
return (
<div>
{isRed && <Counter style="red" />}
{!isRed && <Counter style="blue" />}
{/* Different positions = fresh state */}
</div>
);
}
Now each counter is at a different โaddressโ in the tree. Switching destroys one and creates another!
๐ฏ The Golden Rule
React preserves state when a component stays in the same position in the UI tree.
5๏ธโฃ Resetting State
The Problem: Need a Fresh Start
Sometimes you WANT to reset. Like when:
- A new player joins the game
- You switch to a different chat
- You want to clear a form
Method 1: Different Position
// When isTom changes, Counter resets
{isTom ? (
<Counter person="Tom" />
) : (
<Counter person="Jerry" />
)}
// Different "address" = fresh state
Wait, this looks like the same trick! Yes, but now weโre using it on purpose to reset.
Method 2: The Key Trick ๐
// Give each person their own "locker"
<Counter
key={personId}
person={currentPerson}
/>
When personId changes, React sees a โnewโ counter and resets it!
Real Example: Chat App
function ChatApp() {
const [friendId, setFriendId] =
useState('alice');
return (
<>
<FriendList onSelect={setFriendId} />
{/* Key resets chat when friend changes */}
<ChatBox
key={friendId}
friend={friendId}
/>
</>
);
}
When you click a different friend, the chat clears. The key tells React: โThis is a NEW chat, start fresh!โ
๐ฏ The Golden Rule
Use the
keyprop to force React to reset a componentโs state.
๐ฌ Summary: The Family Rules
| Pattern | What It Does | When to Use |
|---|---|---|
| Lift State Up | Share data via parent | Two siblings need same data |
| Derived State | Calculate, donโt store | Data depends on other data |
| State Structure | Organize cleanly | Avoid bugs & confusion |
| Preserve State | Keep state across renders | Same component, same position |
| Reset State | Fresh start with key |
User switches context |
๐ You Did It!
You now understand the 5 golden patterns of React state:
- ๐ Lift it up when siblings need to share
- ๐งฎ Derive it when you can calculate
- ๐ฆ Structure it to avoid confusion
- ๐ Preserve it by keeping position
- ๐ Reset it with the key prop
Remember: State is like a family. Keep it organized, share when needed, and know when to start fresh!
Happy coding! ๐