Navigate
Search topics, hooks, and fundamentals
What if a field agent could receive classified intel without a single courier?
π΅οΈ Theme: Spy Network
Your app is a spy network. Prop drilling is like passing classified documents through a chain of couriers β every intermediary handles the secret. useContext is an encrypted radio channel: HQ (Provider) broadcasts intel, and any field agent (consumer) tunes in directly. No couriers, no leaks, no middlemen.
Prop drilling is like passing classified documents through a chain of couriers β every intermediary sees the secret, and each one is a liability.
HQHas the classified secretRegional OfficeJust passes the folder alongField StationJust passes the folder alongSafe HouseJust passes the folder alongAgent ShadowActually needs the secretuseContext creates an encrypted channel β HQ broadcasts directly to the field agent. No intermediaries, no leaks.
HQ + ProviderBROADCASTSRegional Officeno clearance neededField Stationno clearance neededSafe Houseno clearance neededAgent ShadowuseContext(IntelCtx)HQ broadcasts β Agent decodes. No couriers, no leaks.
const IntelCtx = createContext(null);
function HQ() {
const [secret] = useState("Rendezvous at dawn");
return (
<IntelCtx.Provider value={secret}>
<RegionalOffice /> {/* no props! */}
</IntelCtx.Provider>
);
}
// Middle layers β clean, no secret prop
function RegionalOffice() { return <FieldStation />; }
function FieldStation() { return <SafeHouse />; }
function SafeHouse() { return <AgentShadow />; }
// Agent decodes the intel directly
function AgentShadow() {
const secret = useContext(IntelCtx);
return <span>Mission: {secret}</span>;
}createContext(defaultValue)Set up the secure frequency β a shared encrypted line for intel.
<IntelCtx.Provider value={data}>HQ sends the classified data β wrap the network that needs access.
useContext(IntelCtx)Any field agent tunes in β read the intel anywhere inside the network.
Every spy needs field practice. Try these operations β each one uses context to share intel across the network.
Relay Station β no mode prop
Safe House β Bravo
COVERTAll clear β operating under the radar
reads mode from context β no props
const ModeCtx = createContext({ mode: "covert", toggle: () => {} });
function HQ() {
const [mode, setMode] = useState("covert");
return (
<ModeCtx.Provider value={{ mode, toggle: () => setMode(m => m === "covert" ? "compromised" : "covert") }}>
<RelayStation /> {/* no mode prop! */}
</ModeCtx.Provider>
);
}
function RelayStation() { return <SafeHouse />; }
function SafeHouse() {
const { mode } = useContext(ModeCtx);
return <div className={mode}>Status: {mode}</div>;
}ID Badge
Shadow
Field Agent
Classified
Comms Panel
Incoming for: Shadow
Field AgentMission Card
π΅οΈShadow
Field AgentAll 3 panels read from AgentContext
const AgentCtx = createContext({ codename: "", clearance: "", avatar: "" });
function HQ() {
const [agent, setAgent] = useState({ codename: "Shadow", clearance: "Field Agent", avatar: "π΅οΈ" });
return (
<AgentCtx.Provider value={agent}>
<IDBadge /> {/* reads codename + avatar */}
<CommsPanel /> {/* reads codename + clearance */}
<MissionCard /> {/* reads all fields */}
</AgentCtx.Provider>
);
}
function IDBadge() {
const { codename, avatar } = useContext(AgentCtx);
return <div>{avatar} {codename}</div>;
}const CipherCtx = createContext({ cipher: "nato", t: translations.nato });
function HQ() {
const [cipher, setCipher] = useState("nato");
return (
<CipherCtx.Provider value={{ cipher, t: translations[cipher] }}>
<BriefingBanner /> {/* reads greeting + briefing */}
<ConfirmButton /> {/* reads confirm text */}
<SignoffFooter /> {/* reads signoff + cipher name */}
</CipherCtx.Provider>
);
}
function BriefingBanner() {
const { t } = useContext(CipherCtx);
return <div>{t.greeting} β {t.briefing}</div>;
}These are the patterns that trip up developers most often. Switch between Wrong and Fixed to compare the code side by side.
function SpyNetworkProvider({ children }) {
const [agents, setAgents] = useState([]);
// New object on every render β ALL consumers re-render
return (
<SpyContext.Provider value={{ agents, setAgents }}>
{children}
</SpyContext.Provider>
);
}// Every consumer re-renders when ANY field changes
const AppContext = createContext(null);
function AppProvider({ children }) {
const [user, setUser] = useState(null);
const [theme, setTheme] = useState("dark");
const [notifications, setNotifications] = useState([]);
return (
<AppContext.Provider value={{
user, setUser, theme, setTheme, notifications, setNotifications
}}>
{children}
</AppContext.Provider>
);
}const SpyContext = createContext(undefined);
function AgentCard() {
// No SpyProvider above this component β gets undefined
const ctx = useContext(SpyContext);
return <div>{ctx.agentName}</div>; // TypeError!
}
// Rendered without wrapping in a provider
function App() {
return <AgentCard />;
}