Subscribe to what you render
Subscribe to the boolean you render; read handler-only values on call.
From vercel-react-best-practices: rerender-derived-state and rerender-defer-reads.
Render per pixel or crossing
Drag the edge or slider, or press Sweep.
useWindowWidth()Bad- Renders
- 0
- Output changed
- 0
- Wasted
- 0
const isMobile = useWindowWidth() < 768useMediaQuery()Good- Renders
- 0
- Output changed
- 0
- Wasted
- 0
useMediaQuery('(max-width: 767px)')function useMediaQuery(query) {
return useSyncExternalStore(
(onChange) => {
const mql = matchMedia(query)
mql.addEventListener('change', onChange)
return () => mql.removeEventListener('change', onChange)
},
() => matchMedia(query).matches,
() => false,
)
}
function Sidebar() {
const isMobile = useMediaQuery('(max-width: 767px)')
return <nav className={isMobile ? 'mobile' : 'desktop'} />
}
Read the URL on click
Change the params, then press Share in both panes.
location.search
useSearchParams()BadsearchParams.get('ref')Read in the handlerGood
new URLSearchParams(location.search)function ShareButton({ chatId }) {
const handleShare = () => {
const ref = new URLSearchParams(window.location.search).get('ref')
shareChat(chatId, { ref })
}
return <button onClick={handleShare}>Share</button>
}
Depend on the boolean
Sweep across 768px and compare effect runs.
[width]Bad- Effect runs
- 0
enableMobileMode()- 0
useEffect(() => { if (width < 768) enableMobileMode() }, [width])[isMobile]Good- Effect runs
- 0
enableMobileMode()- 0
useEffect(() => { if (isMobile) enableMobileMode() }, [isMobile])const isMobile = width < 768
useEffect(() => {
if (isMobile) enableMobileMode()
}, [isMobile])
Why it matters, pros and cons
Why it matters
Render on isMobile, not width. Values only a handler uses: read them on click.
Pros
- One render per crossing, not per pixel
- Handler reads are never stale
- Effects fire once per transition
Cons
- Rendering the number itself still needs a subscription
- Layout-only changes belong in CSS
@media, not JS - Media queries have no server answer; hydration corrects it