Skip to content

Leveraging React Context Across Render Boundaries in Next.js - Lessons from Building a Locale Switcher#138

Open
timgruenewald wants to merge 8 commits into
Zuehlke:mainfrom
timgruenewald:react-context-nextjs-locale-switcher
Open

Leveraging React Context Across Render Boundaries in Next.js - Lessons from Building a Locale Switcher#138
timgruenewald wants to merge 8 commits into
Zuehlke:mainfrom
timgruenewald:react-context-nextjs-locale-switcher

Conversation

@timgruenewald
Copy link
Copy Markdown
Contributor

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.

… 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.
Copy link
Copy Markdown

@kunman93 kunman93 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 shortDescription in 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 SlugMap type (>>)
  • Missing usePathname and Link imports in the LocaleSwitcher snippet
  • Unstable useEffect dependency references (getSlugs, setSlugs)

Language (British English):

  • American → British spelling throughout (localizedlocalised, behaviorbehaviour, summarizesummarise)
  • ConsequentiallyConsequently
  • resp.or (German abbreviation, not English)
  • beforementionedaforementioned
  • at a first glanceat 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
  • LOCALES constant inconsistent with running prose examples

Comment on lines +12 to +14
shortDescription: >-
Implement smooth fade page transitions in React apps using react-router v6 and
framer motion. Learn to handle component lifecycle for seamless animations.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"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`).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 }) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

@kunman93
Copy link
Copy Markdown

kunman93 commented May 8, 2026

I let Copilot do the reviewing. :)

@timgruenewald
Copy link
Copy Markdown
Contributor Author

timgruenewald commented May 20, 2026

Implemented all review feedback for the article and re-checked the file end-to-end.

Addressed items:

  1. Fixed frontmatter short description.
  2. Fixed the Google Search Central URL scheme.
  3. Corrected snippet errors (undefined variable, SlugMap type syntax, missing imports).
  4. Stabilized the hydrator effect dependencies in the example.
  5. Fixed all reported typos/duplicate words and phrasing issues.
  6. Corrected heading punctuation/style and React.cache naming.
  7. Improved heading hierarchy for the failed-approaches section.
  8. Aligned the LOCALES snippet with the prose examples.

Note:

  1. The article prose is now intentionally in American English.

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
@timgruenewald
Copy link
Copy Markdown
Contributor Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants