In modern Next.js applications, state management is essential for maintaining global UI states like modals, sidebars, and theme toggles. While Redux and Zustand are powerful options, React Context API is a lightweight and built-in solution for simpler global states.
In this guide, weβll build a global state manager in Next.js 15 using Context API and TypeScript, with a custom hook for seamless usage.
Step 1: Create a Context for Global State
We start by creating a StateContext to manage a simple open
state (e.g., for a modal or sidebar):
π StateContext.tsx
"use client";
import { createContext, useCallback, useMemo, useState } from "react";
interface StateContextProps {
open: boolean;
handleSetOpen: VoidFunction;
}
const StateContext = createContext<StateContextProps | null>(null);
const StateContextProvider: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const [open, setOpen] = useState<boolean>(false);
const handleSetOpen = useCallback(() => setOpen((prev) => !prev), []);
const contextValue = useMemo<StateContextProps>(
() => ({ open, handleSetOpen }),
[open, handleSetOpen]
);
return (
<StateContext.Provider value={contextValue}>
{children}
</StateContext.Provider>
);
};
export { StateContextProvider, StateContext };
πΉ Why This Works:
β
Uses useCallback
to optimize state updates.
β
Uses useMemo
to prevent unnecessary re-renders.
β
Provides open
and handleSetOpen
globally.
Step 2: Create a Custom Hook for Accessing Context
Instead of using useContext(StateContext)
every time, we create a custom hook to simplify access.
π useStateData.tsx
"use client";
import { StateContext } from "@/contexts/StateContext";
import { useContext } from "react";
export default function useStateData() {
const context = useContext(StateContext);
if (!context) {
throw new Error("useStateData must be used within a StateContextProvider");
}
return context;
}
πΉ Why This is Useful:
β
Encapsulates useContext
to avoid repetitive code.
β
Throws an error if used outside StateContextProvider
.
Step 3: Implement Context in a Next.js 15 Application
Now, letβs use the context in a Next.js 15 component.
π layout.tsx
import { StateContextProvider } from "@/contexts/StateContext";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<StateContextProvider>{children}</StateContextProvider>
</body>
</html>
);
}
β Ensures the context is available throughout the app.
Use the Context in a Component
π ToggleButton.tsx
"use client";
import useStateData from "@/hooks/useStateData";
export default function ToggleButton() {
const { open, handleSetOpen } = useStateData();
return (
<button
onClick={handleSetOpen}
className="px-4 py-2 bg-blue-600 text-white rounded-md"
>
{open ? "Close Sidebar" : "Open Sidebar"}
</button>
);
}
π Sidebar.tsx
"use client";
import useStateData from "@/hooks/useStateData";
export default function Sidebar() {
const { open } = useStateData();
return (
<aside
className={`fixed top-0 left-0 h-full w-64 bg-gray-900 text-white transform ${
open ? "translate-x-0" : "-translate-x-full"
} transition-transform`}
>
<p className="p-4">Sidebar Content</p>
</aside>
);
}
Final Integration in a Page
π page.tsx
import ToggleButton from "@/components/ToggleButton";
import Sidebar from "@/components/Sidebar";
export default function HomePage() {
return (
<main className="flex flex-col items-center justify-center min-h-screen">
<ToggleButton />
<Sidebar />
</main>
);
}
β Now, clicking the button toggles the sidebar state globally!
Final Thoughts
π Why Use Context API for Global UI State?
β
Built into React β No need for external state libraries.
β
Works perfectly in Next.js 15.
β
Great for UI state like modals, sidebars, and themes.
Top comments (0)