Suggest an editImprove this articleRefine the answer for “Context and SSR”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**React Context** lets you store "global" data (`user`, `theme`, `locale`, `auth`) and pass it deep into the component tree without props. **Key point:** yes, context works great with SSR as long as the `Provider` is created inside each SSR request (a unique instance), otherwise data can "leak" between users.Shown above the full answer for quick recall.Answer (EN)Image## What React Context does React Context lets you: - store "global" data (for example, `user`, `theme`, `locale`, `auth`), - pass it deep into the component tree **without props**. Example (client-side): ```javascript const ThemeContext = createContext('light'); function App() { return ( <ThemeContext.Provider value="dark"> <Page /> </ThemeContext.Provider> ); } ``` --- ## What happens during SSR During **Server-Side Rendering**, React: 1. builds the React tree on the server, 2. **renders it with the current context values** into HTML, 3. sends the HTML to the client, 4. the client performs **hydration**, "reviving" that same context in the browser. So **Context participates in rendering the HTML**, and its values determine **what the server puts into the HTML** (for example, a dark theme or a user's name). --- ## Yes, context works with SSR Example: ```javascript // theme-context.ts import { createContext, useContext } from "react"; export const ThemeContext = createContext("light"); export const useTheme = () => useContext(ThemeContext); ``` ```javascript // App.tsx import { ThemeContext } from "./theme-context"; export function App({ theme }: { theme: string }) { return ( <ThemeContext.Provider value={theme}> <Page /> </ThemeContext.Provider> ); } ``` ```javascript // server.tsx import { renderToString } from "react-dom/server"; import { App } from "./App"; app.get("/", (req, res) => { const html = renderToString(<App theme="dark" />); res.send(html); }); ``` The server renders the page in the dark theme right away. During hydration, the client gets the same context (`value="dark"`), and React doesn't re-render. --- ## But! The context must be **unique per request** A context on the server is a **global React object**, so if you use **the same instance** for every user, it can "leak" between requests. ### Example of unsafe code: ```javascript // a shared context for all users - unsafe const UserContext = createContext(null); app.get("/", (req, res) => { UserContext._currentValue = { id: 1, name: "Alice" }; const html = renderToString(<App />); res.send(html); }); ``` → If the next user is "Bob", he might see "Alice's" data. This is a **race condition between requests**. --- ## The right way: "isolate the context per request" Create the `Provider` **inside the render of each SSR request**: ```javascript const UserContext = createContext(null); app.get("/", async (req, res) => { const user = await getUserFromSession(req.cookies.token); const html = renderToString( <UserContext.Provider value={user}> <App /> </UserContext.Provider> ); res.send(html); }); ``` This way, every request gets **its own context instance** and its own data. --- ## How this works in Next.js In Next.js, all of this is automated: ```javascript // layout.tsx export default function RootLayout({ children }) { const theme = cookies().get('theme')?.value || 'light'; return ( <ThemeContext.Provider value={theme}> {children} </ThemeContext.Provider> ); } ``` - On the server, `cookies()` is read on every request. - The context is created **uniquely for rendering the page**. - On the client, it hydrates without desynchronization. --- ## What's important to remember | Feature | Explanation | |---|---| | Works with SSR | Context participates in server-side rendering | | Passed into the HTML | The context value affects the HTML the user sees | | Cannot be stored globally | Otherwise data "leaks" between users | | Hydration must match | The context on the client must have the same value as on the server | | You can use multiple contexts | For example, `UserContext`, `ThemeContext`, `LocaleContext` at the same time | --- ## Conclusion **React Context works great with SSR** as long as: 1. You create the `Provider` inside each SSR request (a unique instance). 2. The context values match between server and client (otherwise hydration "breaks"). 3. You don't perform DOM operations inside context effects on the server. --- ### A short recipe for safe SSR + Context ```javascript // server.tsx renderToString( <AuthProvider user={user}> <ThemeProvider theme="dark"> <App /> </ThemeProvider> </AuthProvider> ); ``` - Every request gets its own `Provider` - Contexts are passed through props - The provider tree is identical on the client and the serverFor the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.