Leveraging React Context Across Render Boundaries in Next.js - Lessons from Building a Locale Switcher#138
Conversation
… Next.js applications - Introduced a comprehensive guide on building a locale switcher using React Context in Next.js. - Discussed challenges related to accessing localized slugs and managing state across render boundaries. - Implemented a Context Hydrator pattern to effectively bridge server-rendered data with client-side components. - Provided code examples for context setup, hydrator component, and locale switcher functionality.
kunman93
left a comment
There was a problem hiding this comment.
Good article overall — the problem is clearly motivated and the solution pattern is well explained. I've left 22 inline comments covering the following categories:
Must fix:
- Wrong
shortDescriptionin frontmatter (copy-pasted from a different article) - Broken hyperlink (missing
https://scheme on the Google Search Central URL) - Two undefined-variable / compile errors in code examples
- TypeScript syntax error in
SlugMaptype (>>) - Missing
usePathnameandLinkimports in theLocaleSwitchersnippet - Unstable
useEffectdependency references (getSlugs,setSlugs)
Language (British English):
- American → British spelling throughout (
localized→localised,behavior→behaviour,summarize→summarise) Consequentially→Consequentlyresp.→or(German abbreviation, not English)beforementioned→aforementionedat a first glance→at first glance
Typos / duplicate words:
- "only be only" — duplicate "only"
- "even that that" — duplicate "that"
- "withing" → "within"
- "into the layout and into the layout" — repeated phrase
- "in the sense of that" → "in the sense that"
Structure:
- Section heading missing
?(# What about React Server Context) - Space before colon in heading (
# The Solution : …) react.cache()→React.cache()- Flat heading hierarchy across the failed-approaches sections
LOCALESconstant inconsistent with running prose examples
| shortDescription: >- | ||
| Implement smooth fade page transitions in React apps using react-router v6 and | ||
| framer motion. Learn to handle component lifecycle for seamless animations. |
There was a problem hiding this comment.
Wrong shortDescription — this appears to be copied from a completely unrelated article (react-router-6-page-transitions):
Implement smooth fade page transitions in React apps using react-router v6 and framer motion. Learn to handle component lifecycle for seamless animations.
Please replace with a short description that accurately summarises this article — e.g. something like:
Learn how to bridge server-rendered CMS data into a client-side locale switcher in Next.js using a React Context hydrator pattern, without global stores or unstable server context APIs.
| # Introduction | ||
|
|
||
| On the project I am currently working on, we are building a Next.js powered web application for a health care provider. | ||
| Some content we show in the web app such as product data or user specific information such as active subscriptions to services is curated via a admin UI, though the main part of the content comes from pages and blog articles as well as images that are fully driven by [Dato, a headless CMS.](https://www.datocms.com/). |
There was a problem hiding this comment.
"a admin UI" → "an admin UI" (the article "a" must become "an" before a vowel sound).
|
|
||
| On the project I am currently working on, we are building a Next.js powered web application for a health care provider. | ||
| Some content we show in the web app such as product data or user specific information such as active subscriptions to services is curated via a admin UI, though the main part of the content comes from pages and blog articles as well as images that are fully driven by [Dato, a headless CMS.](https://www.datocms.com/). | ||
| Consequentially, navigation elements and footer content are curated in the CMS as well, with links representing references to other CMS-driven data records. |
There was a problem hiding this comment.
"Consequentially" → "Consequently". "Consequentially" means "of great consequence / significance"; the intended meaning here is "as a result / therefore", which is "consequently".
| Some content we show in the web app such as product data or user specific information such as active subscriptions to services is curated via a admin UI, though the main part of the content comes from pages and blog articles as well as images that are fully driven by [Dato, a headless CMS.](https://www.datocms.com/). | ||
| Consequentially, navigation elements and footer content are curated in the CMS as well, with links representing references to other CMS-driven data records. | ||
|
|
||
| In order to pave the way for a fully localized user experience, we had to implement a locale resp. language switcher component located in the header of the web application. |
There was a problem hiding this comment.
"locale resp. language switcher" — resp. is a German abbreviation (respektive), not standard English. Replace with "or": "locale or language switcher component".
| In order to pave the way for a fully localized user experience, we had to implement a locale resp. language switcher component located in the header of the web application. | ||
| This dropdown component should always be able to serve the correct, localized URL to the currently viewed page in the other languages the content is available in. | ||
| Now, this would be trivial if the task at hand would be to just switch the locale with the rest of the URL staying the same, e.g. linking from a German article located under `/de/blog/gesund-essen` to the English version of it `/en/blog/gesund-essen`. | ||
| But as [Google documents on "Google Search Central"](developers.google.com/search/docs/crawling-indexing/url-structure#use-your-audiences-language), the best practice when it comes to localized URLs is to use human-readable, descriptive URLs in your audience's language (e.g. in our example `/en/healthy-eating`). |
There was a problem hiding this comment.
The link target is missing the https:// scheme: developers.google.com/search/... — this will not resolve as a clickable hyperlink. Change to:
[Google documents on "Google Search Central"](https://developers.google.com/search/docs/crawling-indexing/url-structure#use-your-audiences-language)
| // app/[locale]/blog/[slug]/page.tsx | ||
| import { LocalizedSlugsHydrator } from "../../components/LocalizedSlugsHydrator"; | ||
|
|
||
| export default async function ProductPage({ params }) { |
There was a problem hiding this comment.
params is missing its TypeScript type annotation. Every other page component in this article is correctly typed — this example should be consistent:
export default async function ProductPage({ params }: { params: Promise<{ locale: string; slug: string }> }) {| const LOCALES: SiteLocale[] = ["de", "fr", "it"]; | ||
|
|
||
| export function LocaleSwitcher() { | ||
| const pathname = usePathname(); |
There was a problem hiding this comment.
usePathname and Link are used in this snippet but neither is imported. For readers new to Next.js these are particularly non-obvious. Please add:
import { usePathname } from "next/navigation";
import Link from "next/link";|
|
||
| import { useLocalizedSlugs } from "@/context/LocalizedSlugsContext"; | ||
|
|
||
| const LOCALES: SiteLocale[] = ["de", "fr", "it"]; |
There was a problem hiding this comment.
The LOCALES array hardcodes ["de", "fr", "it"] (three locales including Italian), but the article's running example throughout only ever mentions German and French. Either align the array with the prose example (["de", "fr"]) or introduce Italian somewhere in the narrative earlier.
There was a problem hiding this comment.
British English spelling — "localize" family — the article consistently uses American English spelling throughout. As the blog uses British English, all of these need updating:
| American (current) | British (required) |
|---|---|
| localized | localised |
| localizing | localising |
| localization | localisation |
| localize | localise |
This affects around 10 occurrences across prose, the frontmatter description, and headings. (Occurrences inside code blocks/backtick literals should remain as-is, since that reflects the actual variable/function names.)
There was a problem hiding this comment.
Heading hierarchy — the sections "What about React Server Context?", "React's cache()", and "Moving away from the idea of 'server context'" are all logically sub-topics of the failed-approaches narrative started by "First Attempt: Global (Server-Side) Stores", yet all four share the same top-level # heading. This flattens the article structure and makes it harder for readers to follow the flow.
Consider demoting those three sections to ## and nesting them under a broader top-level section such as # Why Common Approaches Fall Short, so the structure reads:
# The Challenge
# Why Common Approaches Fall Short
## First Attempt: Global (Server-Side) Stores
## What about React Server Context?
## React's cache()
## Moving away from the idea of "server context"
# The Solution: A Context Hydrator Pattern
# Key Lessons
# Conclusion
|
I let Copilot do the reviewing. :) |
|
Implemented all review feedback for the article and re-checked the file end-to-end. Addressed items:
Note:
Ready for another pass if you want any additional editorial tightening. |
- fix frontmatter short description and broken Google Search Central link - correct code-snippet issues (undefined variable, SlugMap type, missing imports) - improve snippet reliability by stabilizing hydrator effect dependencies - clean up typos, duplicate words, and awkward phrasing - normalize heading punctuation/style and improve section hierarchy - align LOCALES example with prose and keep prose in American English
…n locale switcher article
|
Updated to inline Mermaid in index.md. Replaced the external Mermaid image/link with an in-file Mermaid block to make the diagram easier to edit, review, and maintain. |
…ences and improving section key assignment
In Next.js applications, layouts often need access to data that only becomes available after a nested page has rendered - for example, localized slugs from a headless CMS that are required to build SEO-friendly, localized URLs. This article explores how to bridge that gap with React Context, why global stores and "server contexts" are usually not a good idea, and how a context-based pattern can help manage your state safely across render client/server boundaries.