Skip to main content

Rerender Use Ref Transient Values

Source: .agents/references/coding-standard/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md

Metadata

  • title: Use useRef for Transient Values
  • impact: MEDIUM
  • impactDescription: avoids unnecessary re-renders on frequent updates
  • tags: rerender, useref, state, performance

Content

Use useRef for Transient Values

When a value changes frequently and you don't want a re-render on every update (e.g., mouse trackers, intervals, transient flags), store it in useRef instead of useState. Keep component state for UI; use refs for temporary DOM-adjacent values. Updating a ref does not trigger a re-render.

Incorrect (renders every update):

function Tracker() {
const [lastX, setLastX] = useState(0)

useEffect(() => {
const onMove = (e: MouseEvent) => setLastX(e.clientX)
window.addEventListener('mousemove', onMove)
return () => window.removeEventListener('mousemove', onMove)
}, [])

return (
<div
style={{
position: 'fixed',
top: 0,
left: lastX,
width: 8,
height: 8,
background: 'black',
}}
/>
)
}

Correct (no re-render for tracking):

function Tracker() {
const lastXRef = useRef(0)
const dotRef = useRef<HTMLDivElement>(null)

useEffect(() => {
const onMove = (e: MouseEvent) => {
lastXRef.current = e.clientX
const node = dotRef.current
if (node) {
node.style.transform = `translateX(${e.clientX}px)`
}
}
window.addEventListener('mousemove', onMove)
return () => window.removeEventListener('mousemove', onMove)
}, [])

return (
<div
ref={dotRef}
style={{
position: 'fixed',
top: 0,
left: 0,
width: 8,
height: 8,
background: 'black',
transform: 'translateX(0px)',
}}
/>
)
}