Fix: Improve useIsMobile SSR and initial render consistency#126
Fix: Improve useIsMobile SSR and initial render consistency#126
useIsMobile SSR and initial render consistency#126Conversation
WalkthroughThe Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~5 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/hooks/use-mobile.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/hooks/use-mobile.ts (1)
src/lib/responsive.ts (1)
MOBILE_BREAKPOINT(1-1)
| const [isMobile, setIsMobile] = React.useState<boolean>(() => { | ||
| if (typeof window === 'undefined') { | ||
| return false; // Default for SSR | ||
| } | ||
| return window.innerWidth < MOBILE_BREAKPOINT; // Initial value for client | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/hooks/use-mobile.tsRepository: Authormaton/authormaton
Length of output: 1049
🏁 Script executed:
rg -n "useIsMobile" --type=ts --type=tsx -C3Repository: Authormaton/authormaton
Length of output: 94
🏁 Script executed:
rg -n "useIsMobile" --type=ts -C3Repository: Authormaton/authormaton
Length of output: 6544
🏁 Script executed:
rg -n "useIsMobile" -C3Repository: Authormaton/authormaton
Length of output: 6544
🏁 Script executed:
sed -n '55,80p' src/components/ui/sidebar.tsxRepository: Authormaton/authormaton
Length of output: 958
🏁 Script executed:
sed -n '14,40p' src/components/models/projects/ProjectsTable.tsxRepository: Authormaton/authormaton
Length of output: 908
🏁 Script executed:
sed -n '8,30p' src/components/layouts/GeneralLayout.tsxRepository: Authormaton/authormaton
Length of output: 913
🏁 Script executed:
sed -n '14,60p' src/components/models/projects/ProjectsTable.tsxRepository: Authormaton/authormaton
Length of output: 1433
🏁 Script executed:
rg -n "suppressHydrationWarning" --type=tsRepository: Authormaton/authormaton
Length of output: 143
🏁 Script executed:
rg -n "suppressHydrationWarning"Repository: Authormaton/authormaton
Length of output: 143
Hydration mismatch from lazy useState initializer reading window
The lazy initializer with typeof window === 'undefined' is runtime-safe for SSR, but it causes server and initial client renders to diverge:
- On the server,
isMobileis alwaysfalse. - On the client during hydration, the initializer may return
trueifinnerWidth < 768.
This causes hydration mismatches in components that conditionally render based on isMobile:
- GeneralLayout.tsx renders
<Sheet>on mobile but<div>on desktop based on this value - ProjectsTable.tsx renders a grid on mobile but
<BasicTable>on desktop based on this value
Both components will render different markup on the server versus the client, triggering hydration warnings and potential layout shifts after the effect updates.
Initialize to a constant value (e.g., useState(false)) and rely on the effect to update after mount, ensuring server and first hydration render are consistent. Alternatively, make these components client-only or add suppressHydrationWarning if the brief mismatch is acceptable.
🤖 Prompt for AI Agents
In src/hooks/use-mobile.ts around lines 6 to 11, the lazy useState initializer
reads window causing server vs initial client render divergence; change the
initial state to a constant (e.g., useState(false)) so SSR and first hydration
produce the same output, then in a useEffect run only on mount to read
window.innerWidth and setIsMobile accordingly, and also add a resize listener
inside that effect to update on viewport changes with proper cleanup on unmount.
Overview: This PR updates the
useIsMobilehook to ensure consistent behavior during server-side rendering (SSR) and on initial client-side renders.Changes
useStateinitialization insrc/hooks/use-mobile.tsto check forwindowavailability. Ifwindowisundefined(SSR), it defaults tofalse. Otherwise, it directly calculates the initialisMobilestate based onwindow.innerWidth.checkIsMobile()call in theuseEffecthook, as the initial state is now correctly set duringuseStateinitialization.Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.