π§ How I Built Global State in React Without Redux
Ever struggled with managing modals, sidebars, or navbar state across your React app?
Let me show you how I built a global state system using just React context + reducer. No Redux. No headache.
π οΈ Problem I faced:
In my app, I needed to:
- Show/hide a modal
- Toggle the navbar
But I didnβt want to pass state and functions down multiple levels.
So I built a shared global context.
βοΈ Step 1: Create the Global Context
// GlobalStateContext.tsx
"use client";
import React, {
createContext,
useContext,
useReducer,
useCallback,
useMemo,
ReactNode,
} from "react";
const initialState = {
isModalOpen: false,
isNavbarOpen: false,
};
function reducer(state, action) {
switch (action.type) {
case "OPEN_MODAL":
return { ...state, isModalOpen: true };
case "CLOSE_MODAL":
return { ...state, isModalOpen: false };
case "TOGGLE_NAVBAR":
return { ...state, isNavbarOpen: !state.isNavbarOpen };
default:
return state;
}
}
const GlobalStateContext = createContext();
export function GlobalStateProvider({ children }) {
const [state, dispatch] = useReducer(reducer, initialState);
const openModal = useCallback(() => dispatch({ type: "OPEN_MODAL" }), []);
const closeModal = useCallback(() => dispatch({ type: "CLOSE_MODAL" }), []);
const toggleNavbar = useCallback(() => dispatch({ type: "TOGGLE_NAVBAR" }), []);
const value = useMemo(() => ({
...state,
openModal,
closeModal,
toggleNavbar,
}), [state]);
return (
<GlobalStateContext.Provider value={value}>
{children}
</GlobalStateContext.Provider>
);
}
export function useGlobalState() {
const context = useContext(GlobalStateContext);
if (!context) throw new Error("Wrap your app with GlobalStateProvider.");
return context;
}
β‘ Step 2: Wrap Your App with the Provider
// layout.tsx or _app.tsx
import { GlobalStateProvider } from "@/context/GlobalStateContext";
export default function Layout({ children }) {
return (
<html>
<body>
<GlobalStateProvider>
{children}
</GlobalStateProvider>
</body>
</html>
);
}
π¦ Step 3: Use It Anywhere in Your App
β Modal Example
"use client";
import { useGlobalState } from "@/context/GlobalStateContext";
import { Button } from "@/components/ui/button";
export default function ModalExample() {
const { isModalOpen, openModal, closeModal } = useGlobalState();
return (
<>
<Button onClick={openModal}>Show Modal</Button>
{isModalOpen && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center">
<div className="bg-white p-6 rounded shadow">
<h2 className="text-lg font-bold">I'm a modal</h2>
<Button className="mt-4" onClick={closeModal}>Close</Button>
</div>
</div>
)}
</>
);
}
β Navbar Toggle Example
"use client";
import { useGlobalState } from "@/context/GlobalStateContext";
import { Button } from "@/components/ui/button";
export default function NavbarToggle() {
const { isNavbarOpen, toggleNavbar } = useGlobalState();
return (
<Button onClick={toggleNavbar}>
{isNavbarOpen ? "Close Navbar" : "Open Navbar"}
</Button>
);
}
π§© Why This Is Better Than Redux (For Me)
β
No third-party lib
β
Fully typed
β
Simple to read
β
Works with Next.js, ShadCN, anything
Final Thoughts
If you're building a simple app with modals, dropdowns, navbar toggles β this pattern is gold.
You can always scale it later.
Start small. Think simple. Ship fast.
About Tamjid Mostafa
π Turning Websites into Growth Machines
I help B2B service providers build custom websites that work for them β not just look pretty.
Think: book more meetings, qualify leads, answer FAQs β all on autopilot. βοΈπ€
π» With 3+ years of experience as a full-stack developer, I craft fast, scalable, and conversion-focused web apps using:
Next.js, React, Tailwind CSS, Framer Motion, and MongoDB.
π― My focus?
β Clean UI β¨
β Smooth UX animations ποΈ
β Built-in automation & smart workflows π
β SEO & speed-optimized delivery β‘
π€ Iβve worked with clients long-term β not just shipping code, but solving real business problems. Whether youβre a founder, coach, or agency β Iβll help you launch a website that actually grows your business. π