74 lines
1.7 KiB
Markdown
74 lines
1.7 KiB
Markdown
---
|
|
|
|
title: Use useRef for Transient Values
|
|
impact: MEDIUM
|
|
impactDescription: 避免频繁更新时触发不必要的重渲染
|
|
tags: rerender, useref, state, performance
|
|
|
|
## 使用 useRef 存储临时值
|
|
|
|
当一个值变化频繁,且你不希望每次更新都触发重渲染时(例如鼠标追踪器、定时器、临时标记),应将其存储在 `useRef` 中,而非 `useState`。用组件状态管理 UI,用 ref 管理临时的 DOM 相关值。更新 ref 不会触发重渲染。
|
|
|
|
**错误做法(每次更新都渲染):**
|
|
|
|
```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',
|
|
}}
|
|
/>
|
|
)
|
|
}
|
|
```
|
|
|
|
**正确做法(追踪时不触发重渲染):**
|
|
|
|
```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)',
|
|
}}
|
|
/>
|
|
)
|
|
}
|
|
```
|