74 lines
1.7 KiB
Markdown
74 lines
1.7 KiB
Markdown
---
|
|
title: Use useRef for Transient Values
|
|
impact: MEDIUM
|
|
impactDescription: avoids unnecessary re-renders on frequent updates
|
|
tags: rerender, useref, state, performance
|
|
---
|
|
|
|
## 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):**
|
|
|
|
```tsx
|
|
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):**
|
|
|
|
```tsx
|
|
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)',
|
|
}}
|
|
/>
|
|
)
|
|
}
|
|
```
|