Loading content…
Loading content…
Learn how to lift state, avoid prop drilling, use Context API, and manage state at scale with Zustand
import { useState } from "react";
// Child 1: The Controller
const TempControls = ({ temp, onTempChange }: { temp: number; onTempChange: (t: number) => void }) => {
return (
<div className="flex gap-2">
<button onClick={() => onTempChange(temp - 1)} className="px-3 py-1 bg-red-100 rounded">-</button>
<button onClick={() => onTempChange(temp + 1)} className="px-3 py-1 bg-green-100 rounded">+</button>
</div>
);
};
// Child 2: The Display
const TempDisplay = ({ temp }: { temp: number }) => {
return <p className="text-lg font-bold">Current Temperature: {temp}°C</p>;
};
// Parent Component: Holds the source of truth (State)
export default function WeatherApp() {
const [temperature, setTemperature] = useState(20);
return (
<div className="p-4 border rounded-xl bg-white shadow-sm max-w-sm">
<h3 className="font-semibold mb-2">Weather App</h3>
<TempDisplay temp={temperature} />
<TempControls temp={temperature} onTempChange={setTemperature} />
</div>
);
}
WeatherApp, we ensure both child components stay in sync.import { createContext, useContext, useState, ReactNode } from "react";
// 1. Create the Context with a default value
interface ThemeContextType {
theme: "light" | "dark";
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
// 2. Create the Provider Component
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
const [theme, setTheme] = useState<"light" | "dark">("light");
const toggleTheme = () => {
setTheme((prev) => (prev === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
// 3. Create a Custom Hook to consume the Context safely
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
};
// 4. Use it in any child component
export const ThemeButton = () => {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme} className="p-2 border rounded">
Active Theme: {theme === "light" ? "☀️ Light" : "🌙 Dark"}
</button>
);
};
Common Pitfall
| Feature | Context API | Zustand | Redux Toolkit |
|---|---|---|---|
| Performance | Triggers re-renders on all consumers | High (renders only selected properties) | High (renders only selected properties) |
| Boilerplate | Low | Very Low (No provider required) | Medium (Actions, reducers, store config) |
| Learning Curve | Low | Easy | Medium-High |
| DevTools | React DevTools only | Redux DevTools support | Advanced Redux DevTools |
import { create } from "zustand";
interface CartItem {
id: string;
name: string;
price: number;
quantity: number;
}
interface CartState {
items: CartItem[];
addToCart: (item: Omit<CartItem, "quantity">) => void;
removeFromCart: (id: string) => void;
clearCart: () => void;
}
// Create the global store
export const useCartStore = create<CartState>((set) => ({
items: [],
addToCart: (product) =>
set((state) => {
const existingItem = state.items.find((item) => item.id === product.id);
if (existingItem) {
return {
items: state.items.map((item) =>
item.id === product.id
? { ...item, quantity: item.quantity + 1 }
: item
),
};
}
return { items: [...state.items, { ...product, quantity: 1 }] };
}),
removeFromCart: (id) =>
set((state) => ({
items: state.items.filter((item) => item.id !== id),
})),
clearCart: () => set({ items: [] }),
}));
import { useCartStore } from "./cartStore";
export const CartCounter = () => {
// Selector: This component only re-renders if the length of items changes!
const itemCount = useCartStore((state) => state.items.length);
return <div className="badge">Items: {itemCount}</div>;
};
export const AddButton = ({ product }) => {
const addToCart = useCartStore((state) => state.addToCart);
return (
<button onClick={() => addToCart(product)}>
Add to Cart
</button>
);
};
Senior Developer Wisdom
state => state.items) rather than destructuring the entire store state. This ensures components only re-render when the specific selected value changes, optimizing app speed.State Management Checklist
Marking it complete updates your roadmap progress percentage.