Skip to content

fix(app): avoid React #418 hydration mismatch from personalized site settings#18183

Draft
posthog[bot] wants to merge 1 commit into
masterfrom
posthog-code/fix-418-hydration-site-settings
Draft

fix(app): avoid React #418 hydration mismatch from personalized site settings#18183
posthog[bot] wants to merge 1 commit into
masterfrom
posthog-code/fix-418-hydration-site-settings

Conversation

@posthog

@posthog posthog Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Changes

The server renders every page with fixed defaults — <body className="light" data-wallpaper="keyboard-garden"> in src/html.tsx, and matching light/posthog/modern/keyboard-garden siteSettings in src/context/App.tsx. On the client, though, App.tsx read localStorage (and window.__theme) synchronously into its initial siteSettings state. A visitor whose saved settings differ from those defaults (dark theme, the "boring" experience, classic skin, a different wallpaper) therefore produced a first client render that diverged from the SSR HTML — which is exactly what triggers a React #418 hydration mismatch. The mismatch is benign (React regenerates the affected subtree), but it's noise in error tracking.

This defers the personalized settings so the first client render reproduces the SSR defaults, then swaps in the stored settings via a layout effect after hydration — the same post-mount two-pass pattern the codebase already uses for layoutLogic.websiteTheme. Key detail: the internal siteSettings state keeps the real stored values, so the body-attribute and persistence effects stay correct, and theme-init.js has already applied theme/skin/wallpaper to <body> before hydration — so for CSS-driven personalization (dark mode, wallpaper, skin) the swap is invisible.

Why: a visitor with non-default theme/skin settings was hitting React #418 on load. Impact is negligible (a benign, self-recovering mismatch), but this removes the error-tracking noise at the root.

Verification: pnpm prettier --check and tsc --noEmit pass. The symptom is a production-SSR/hydration-only warning; the fix is verified by reasoning + matching the existing working websiteTheme deferral pattern rather than a full production build.

Checklist

  • I've read the docs and/or content style guides.
  • Words are spelled using American English
  • Use relative URLs for internal links
  • I've checked the pages added or changed in the Vercel preview build
  • If I moved a page, I added a redirect in vercel.json

Created with PostHog Code from an inbox report.

…settings

The server renders the app with fixed defaults (light theme, "posthog"
experience, modern skin, keyboard-garden wallpaper), but App.tsx read
localStorage synchronously into the initial `siteSettings` state. A visitor
whose stored settings differ produced a first client render that diverged
from the SSR HTML, triggering a React #418 hydration mismatch.

Expose the personalized settings to consumers only after hydration (matching
the existing post-mount pattern already used for layoutLogic.websiteTheme).
The first client render now reproduces the SSR defaults, then swaps in the
real settings via a layout effect. The internal `siteSettings` state keeps the
real values so the body-attribute and persistence effects stay correct, and
theme-init.js has already applied theme/skin/wallpaper to <body>, so the swap
is invisible for CSS-driven personalization.

Generated-By: PostHog Code
Task-Id: f2fe526d-694f-4d16-9eca-51558134a548
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Deploy preview

Status Details Updated (UTC)
🟢 Ready View preview Jul 05, 2026 04:37AM

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Bundle report

Total JS (gzip)

6.29 MiB (+0.1 KiB / +0.0%)

Eager graph (static-import closure per entrypoint)

Entrypoint Eager size Budget Modules
app 24.22 MiB (+1.7 KiB / +0.0%) report-only 5516
Largest modules in the app closure
Module Size
css ./node_modules/.pnpm/css-loader@5.2.7_webpack@5.101.3/node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[1]!./node_modules/.pnpm/postcss-loader@4.3.0_postcss@8.5.6_webpack@5.101.3/node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[8].oneOf[1].use[2]!./src/styles/global.css 708.1 KiB
./src/components/Stickers/Stickers.tsx 696.4 KiB
./.cache/caches/gatsby-plugin-mdx/mdx-scopes-dir/31a094f140f119e73085d847ae81b99b.js + 2 modules 584.4 KiB
./node_modules/.pnpm/@radix-ui+react-icons@1.3.2_react@18.3.1/node_modules/@radix-ui/react-icons/dist/react-icons.esm.js 481.4 KiB
./node_modules/.pnpm/@codemirror+view@6.38.2/node_modules/@codemirror/view/dist/index.js 458.1 KiB
./node_modules/.pnpm/rehype-raw@7.0.0/node_modules/rehype-raw/lib/index.js + 29 modules 395.1 KiB
./node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.cjs.js 364.8 KiB
./node_modules/.pnpm/@posthog+icons@0.36.6_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js 354.8 KiB
./src/hooks/useCustomers.tsx + 54 modules 353.9 KiB
./node_modules/.pnpm/react-markdown@8.0.7_@types+react@16.14.66_react@18.3.1/node_modules/react-markdown/lib/react-markdown.js + 88 modules 351.4 KiB
./node_modules/.pnpm/cloudinary-core@2.14.0_lodash@4.17.21/node_modules/cloudinary-core/cloudinary-core.js 281.9 KiB
./src/components/ProductComparisonTable/index.tsx + 116 modules 267.6 KiB
./node_modules/.pnpm/@codesandbox+sandpack-react@2.20.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@codesandbox/sandpack-react/dist/index.mjs 266.6 KiB
./node_modules/.pnpm/d3@7.9.0/node_modules/d3/src/index.js + 208 modules 247.4 KiB
./src/components/Pricing/PricingSlider/Slider.tsx + 87 modules 239.9 KiB

Eager-graph budgets are report-only until a baseline is established. Sizes are gzip of public/**/*.js; eager size is webpack module source bytes.

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.

0 participants