在 React 中,管理組件實例和它們的內部狀態有時可能相當複雜,特別是當你需要更多對組件的控制時。useImperativeHandle
提供了一種方法,通過 ref 從子組件向父組件暴露特定的實例值或一組函數。
基本語法如下:
useImperativeHandle(ref, createHandle, [deps]);
假設你有一個自定義輸入組件,希望父組件在點擊按鈕時能夠聚焦此輸入框。通常情況下,內部輸入元素的 DOM 對父組件是隱藏的。使用useImperativeHandle
,你可以輕鬆創建並暴露自定義聚焦方法。
例如:
子組件:
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
const FancyInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} {...props} />;
});
父組件:
import React, { useRef } from 'react';
import FancyInput from './FancyInput';
function App() {
const inputRef = useRef();
return (
<>
<FancyInput ref={inputRef} />
<button onClick={() => inputRef.current.focus()}>
Focus the input
</button>
</>
);
}
在這個例子中,FancyInput
組件使用useImperativeHandle
向任何使用 ref 與FancyInput
互動的父組件暴露focus
方法。
對於一個媒體播放器組件,你可以暴露如播放(play)、暫停(pause)或重置(reset)等方法。
子組件:
const MediaPlayer = forwardRef((props, ref) => {
const audioRef = useRef();
useImperativeHandle(ref, () => ({
play: () => {
audioRef.current.play();
},
pause: () => {
audioRef.current.pause();
},
reset: () => {
audioRef.current.currentTime = 0;
}
}));
return <audio ref={audioRef} src={props.src} controls />;
});
父組件:
import React, { useRef } from 'react';
import MediaPlayer from './MediaPlayer';
function App() {
const mediaRef = useRef();
return (
<>
<MediaPlayer ref={mediaRef} src="example.mp3" />
<button onClick={() => mediaRef.current.play()}>
Play
</button>
<button onClick={() => mediaRef.current.pause()}>
Pause
</button>
<button onClick={() => mediaRef.current.reset()}>
Reset
</button>
</>
);
}
在此例中,MediaPlayer
組件使用useImperativeHandle
向任何使用 ref 與MediaPlayer
互動的父組件暴露控制媒體播放的方法。父組件提供了播放、暫停和重置的按鈕。
useImperativeHandle
應謹慎使用。React 的聲明式特性應始終是你的首選工具。當你絕對需要以一種無法通過 props 或狀態進行的方式與子組件互動時,再考慮使用useImperativeHandle
。例如,當與第三方 DOM 庫集成或管理焦點、選擇或動畫時。
useImperativeHandle
提供了一種強大的方式來與子組件進行互動。通過暴露子組件的特定功能,你可以保持組件間清晰且可管理的接口,增強代碼的可擴展性和可讀性。關鍵是適度使用它來補充 React 的聲明式本質,而不是替代它。
其他關於hook系列文章:
關於useDeferredValue 關於useImperativeHandle 關於useSyncExternalStore 關於useTransition