Shared state across layouts lets different pages or sections of your app use the same data or settings. This helps keep things consistent and saves you from repeating code.
Shared state across layouts in NextJS
'use client'; import { createContext, useContext, useState } from 'react'; const SharedStateContext = createContext(); export function SharedStateProvider({ children }) { const [state, setState] = useState(false); return ( <SharedStateContext.Provider value={{ state, setState }}> {children} </SharedStateContext.Provider> ); } export function useSharedState() { return useContext(SharedStateContext); }
This pattern uses React Context to share state.
Wrap your layouts or pages with SharedStateProvider to give them access.
import { SharedStateProvider } from './SharedStateContext'; export default function RootLayout({ children }) { return ( <html lang="en"> <body> <SharedStateProvider> {children} </SharedStateProvider> </body> </html> ); }
'use client'; import { useSharedState } from './SharedStateContext'; export default function Header() { const { state, setState } = useSharedState(); return ( <header> <button onClick={() => setState(!state)}> Toggle: {state ? 'On' : 'Off'} </button> </header> ); }
This example shows how to share a dark mode setting across layouts and pages. The SharedStateProvider wraps the app. The Header toggles the mode. The Page shows the current mode and changes style accordingly.
'use client'; import { createContext, useContext, useState } from 'react'; const SharedStateContext = createContext(); export function SharedStateProvider({ children }) { const [darkMode, setDarkMode] = useState(false); return ( <SharedStateContext.Provider value={{ darkMode, setDarkMode }}> {children} </SharedStateContext.Provider> ); } export function useSharedState() { return useContext(SharedStateContext); } // RootLayout.js export default function RootLayout({ children }) { return ( <html lang="en"> <body> <SharedStateProvider> {children} </SharedStateProvider> </body> </html> ); } // Header.js 'use client'; import { useSharedState } from './SharedStateContext'; export default function Header() { const { darkMode, setDarkMode } = useSharedState(); return ( <header style={{ padding: '1rem', backgroundColor: darkMode ? '#222' : '#eee', color: darkMode ? '#eee' : '#222' }}> <button onClick={() => setDarkMode(!darkMode)} aria-label="Toggle dark mode"> {darkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode'} </button> </header> ); } // Page.js 'use client'; import Header from './Header'; import { useSharedState } from './SharedStateContext'; export default function Page() { const { darkMode } = useSharedState(); return ( <main style={{ padding: '1rem', backgroundColor: darkMode ? '#333' : '#fff', color: darkMode ? '#ddd' : '#000' }}> <Header /> <p>The current mode is {darkMode ? 'Dark' : 'Light'}.</p> </main> ); }
Always wrap your app or layouts with the provider to share state properly.
Use React Context carefully; too much shared state can slow your app.
For bigger apps, consider state management libraries or server state solutions.
Shared state lets multiple layouts and pages use the same data easily.
React Context with a provider and custom hook is a simple way to share state in Next.js.
Wrap your root layout with the provider and use the custom hook inside components.
Practice
Solution
Step 1: Understand the purpose of shared state
Shared state means multiple parts of the app can use the same data without duplication.Step 2: Identify the benefit in Next.js layouts
Sharing state across layouts lets pages and layouts access common data easily, improving consistency.Final Answer:
It allows multiple layouts and pages to access the same data easily. -> Option AQuick Check:
Shared state = common data access [OK]
- Confusing shared state with styling or caching
- Thinking shared state blocks navigation
- Assuming shared state only affects server speed
Solution
Step 1: Recall React Context usage
React Context requires wrapping components with a Provider to share state.Step 2: Apply to Next.js layouts
Wrapping the root layout with the Provider shares state across all nested layouts and pages.Final Answer:
Wrap the root layout with a Context Provider component. -> Option BQuick Check:
Provider wraps root layout = shared state [OK]
- Trying to add state without a Provider
- Using server props instead of Context for shared state
- Confusing CSS imports with state management
const CountContext = React.createContext();
function CountProvider({ children }) {
const [count, setCount] = React.useState(0);
return (
<CountContext.Provider value={{ count, setCount }}>
{children}
</CountContext.Provider>
);
}
function Button() {
const { count, setCount } = React.useContext(CountContext);
return <button onClick={() => setCount(count + 1)}>Clicked {count} times</button>;
}
// Root layout wraps children with <CountProvider>Solution
Step 1: Understand context sharing
The CountProvider shares count state via context to all nested components.Step 2: Analyze button behavior
Clicking the button calls setCount to increase count, updating all components using the context.Final Answer:
Clicking the button increases the count visible in all layouts sharing the context. -> Option AQuick Check:
Context state update = shared count change [OK]
- Thinking state updates are local to Button only
- Assuming missing Provider causes error here
- Believing count resets on each click
Solution
Step 1: Check how nested layouts access context
Nested layouts must use React.useContext or a custom hook to read shared state.Step 2: Identify common mistake
Forgetting to call useContext means no access to the shared data, even if Provider is correct.Final Answer:
You forgot to use the custom hook or React.useContext inside nested layouts. -> Option CQuick Check:
Missing useContext call = no access [OK]
- Placing Provider too deep, not at root
- Confusing useState with useContext
- Importing context incorrectly from non-JS files
Solution
Step 1: Understand combining server data with shared state
User info fetched server-side should be stored in a shared client state for consistent access.Step 2: Use Context Provider at root layout
Wrapping root layout with a Provider holding user state allows all layouts to access and update it.Step 3: Update state client-side after server fetch
Fetching user info via server actions or API routes and updating context keeps user logged in across layouts.Final Answer:
Wrap the root layout with a Context Provider that holds user state, and update it client-side after fetching user info in a server action or API route. -> Option DQuick Check:
Context + server fetch = shared auth state [OK]
- Passing user data only via props without shared state
- Using local state per layout causing inconsistent user info
- Trying to store user info in CSS or non-JS files
Ready to prove it?
Pass the test and this pattern moves unknown
