Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Apply 62 React and Next.js performance optimization rules from Vercel Engineering
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/rendering-hydration-no-flicker.md
1---2title: Prevent Hydration Mismatch Without Flickering3impact: MEDIUM4impactDescription: avoids visual flicker and hydration errors5tags: rendering, ssr, hydration, localStorage, flicker6---78## Prevent Hydration Mismatch Without Flickering910When rendering content that depends on client-side storage (localStorage, cookies), avoid both SSR breakage and post-hydration flickering by injecting a synchronous script that updates the DOM before React hydrates.1112**Incorrect (breaks SSR):**1314```tsx15function ThemeWrapper({ children }: { children: ReactNode }) {16// localStorage is not available on server - throws error17const theme = localStorage.getItem('theme') || 'light'1819return (20<div className={theme}>21{children}22</div>23)24}25```2627Server-side rendering will fail because `localStorage` is undefined.2829**Incorrect (visual flickering):**3031```tsx32function ThemeWrapper({ children }: { children: ReactNode }) {33const [theme, setTheme] = useState('light')3435useEffect(() => {36// Runs after hydration - causes visible flash37const stored = localStorage.getItem('theme')38if (stored) {39setTheme(stored)40}41}, [])4243return (44<div className={theme}>45{children}46</div>47)48}49```5051Component first renders with default value (`light`), then updates after hydration, causing a visible flash of incorrect content.5253**Correct (no flicker, no hydration mismatch):**5455```tsx56function ThemeWrapper({ children }: { children: ReactNode }) {57return (58<>59<div id="theme-wrapper">60{children}61</div>62<script63dangerouslySetInnerHTML={{64__html: `65(function() {66try {67var theme = localStorage.getItem('theme') || 'light';68var el = document.getElementById('theme-wrapper');69if (el) el.className = theme;70} catch (e) {}71})();72`,73}}74/>75</>76)77}78```7980The inline script executes synchronously before showing the element, ensuring the DOM already has the correct value. No flickering, no hydration mismatch.8182This pattern is especially useful for theme toggles, user preferences, authentication states, and any client-only data that should render immediately without flashing default values.83