Hooks: useRef
## `useRef` 的語法
```jsx
import { useRef } from 'react';
const ref = useRef(initialValue);
```
`useRef` 會回傳一個物件:
```js
{
current: initialValue
}
```
之後可以透過 `ref.current` 讀取或修改其內容。
### 常見用途
1. **取得 DOM 元素**
```jsx
const inputRef = useRef(null);
<input ref={inputRef} />
```
使用時:
```js
inputRef.current.focus();
```
2. **保存不希望觸發重新渲染的資料**
```jsx
const timerId = useRef(null);
```
修改 `timerId.current` 不會讓元件重新渲染。
3. **保存元件實例或第三方函式庫物件**
例如影音播放器、Canvas、地圖元件等。
### 注意事項
- `ref.current` 的值會在元件重新渲染之間保留。
- 修改 `ref.current` 不會觸發重新渲染。
- DOM ref 在元件第一次 render 時通常是 `null`,掛載後才會有值。
- 不應該在 render 過程中直接操作 DOM,應在事件處理函式或 `useEffect` 中使用。
---
## 範例:影音播放控制器
以下範例使用 `useRef` 取得 `<video>` 元素,並控制播放、暫停、停止與音量。
```jsx
import { useRef, useState } from 'react';
function VideoPlayer() {
// 用來保存 video DOM 元素的參考
const videoRef = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
const handlePlay = async () => {
if (videoRef.current) {
await videoRef.current.play();
setIsPlaying(true);
}
};
const handlePause = () => {
if (videoRef.current) {
videoRef.current.pause();
setIsPlaying(false);
}
};
const handleStop = () => {
if (videoRef.current) {
videoRef.current.pause();
videoRef.current.currentTime = 0;
setIsPlaying(false);
}
};
const handleVolumeChange = (event) => {
if (videoRef.current) {
videoRef.current.volume = event.target.value;
}
};
return (
<div>
<video
ref={videoRef}
width="500"
src="/videos/demo.mp4"
controls={false}
/>
<div>
<button onClick={handlePlay} disabled={isPlaying}>
播放
</button>
<button onClick={handlePause} disabled={!isPlaying}>
暫停
</button>
<button onClick={handleStop}>
停止
</button>
<label>
音量:
<input
type="range"
min="0"
max="1"
step="0.1"
defaultValue="1"
onChange={handleVolumeChange}
/>
</label>
</div>
</div>
);
}
export default VideoPlayer;
```
關鍵部分是:
```jsx
const videoRef = useRef(null);
<video ref={videoRef} />
```
React 掛載 `<video>` 後,`videoRef.current` 就會指向該 DOM 元素,因此可以呼叫原生影音 API:
```js
videoRef.current.play();
videoRef.current.pause();
videoRef.current.currentTime = 0;
videoRef.current.volume = 0.5;
```
這類操作如果只靠 `useState` 儲存 DOM 元素,會比較不適合;`useRef` 正是用來保存這種不需要觸發重新渲染的參考值。
相關學習地圖、教學課程
F2E 網站前端工程