useImperativeHandle
是一個 React Hook,可讓你自訂公開為 ref 的控制代碼。
useImperativeHandle(ref, createHandle, dependencies?)
參考
useImperativeHandle(ref, createHandle, dependencies?)
在元件的頂層呼叫 useImperativeHandle
來自訂它公開的 ref 控制代碼
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
// ...
參數
-
ref
:你從forwardRef
渲染函式接收的第二個參數 ref。 -
createHandle
:一個不接受任何參數並返回你想公開的 ref 控制代碼的函式。該 ref 控制代碼可以是任何類型。通常,你會返回一個包含你想公開方法的物件。 -
選用
dependencies
:createHandle
程式碼內參考的所有反應值的列表。反應值包括 props、狀態,以及直接在元件主體內宣告的所有變數和函式。如果你的程式碼檢查器已針對 React 進行設定,它將驗證每個反應值是否已正確指定為依賴項。依賴項列表必須具有固定數量的項目,並且必須像[dep1, dep2, dep3]
一樣內嵌撰寫。React 將使用Object.is
比較將每個依賴項与其先前值進行比較。如果重新渲染導致某些依賴項發生更改,或者你省略了此參數,則你的createHandle
函式將重新執行,並且新建立的控制代碼將被指派給 ref。
回傳值
useImperativeHandle
回傳 undefined
。
用法
將自定義 ref 控制代碼暴露給父組件
預設情況下,組件不會將其 DOM 節點暴露給父組件。例如,如果您希望 MyInput
的父組件能夠存取 <input>
DOM 節點,您必須使用 forwardRef
來選擇加入:
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} ref={ref} />;
});
透過上面的程式碼,指向 MyInput
的 ref 將會收到 <input>
DOM 節點。 但是,您可以改為暴露自定義值。要自定義暴露的控制代碼,請在組件的頂層呼叫 useImperativeHandle
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
return <input {...props} />;
});
請注意,在上面的程式碼中,ref
不再轉發到 <input>
。
例如,假設您不想暴露整個 <input>
DOM 節點,但您想暴露它的兩個方法:focus
和 scrollIntoView
。要做到這一點,請將真實的瀏覽器 DOM 保留在一個單獨的 ref 中。然後使用 useImperativeHandle
暴露一個只包含您希望父組件呼叫的方法的控制代碼
import { forwardRef, useRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input {...props} ref={inputRef} />;
});
現在,如果父組件取得了 MyInput
的 ref,它將能夠在其上呼叫 focus
和 scrollIntoView
方法。但是,它將無法完全存取底層的 <input>
DOM 節點。
import { useRef } from 'react'; import MyInput from './MyInput.js'; export default function Form() { const ref = useRef(null); function handleClick() { ref.current.focus(); // This won't work because the DOM node isn't exposed: // ref.current.style.opacity = 0.5; } return ( <form> <MyInput placeholder="Enter your name" ref={ref} /> <button type="button" onClick={handleClick}> Edit </button> </form> ); }
暴露您自己的指令式方法
您透過指令式控制代碼暴露的方法不必與 DOM 方法完全相同。例如,這個 Post
組件透過指令式控制代碼暴露了一個 scrollAndFocusAddComment
方法。這讓父組件 Page
在您點擊按鈕時滾動評論列表*並*將焦點放在輸入欄位上
import { useRef } from 'react'; import Post from './Post.js'; export default function Page() { const postRef = useRef(null); function handleClick() { postRef.current.scrollAndFocusAddComment(); } return ( <> <button onClick={handleClick}> Write a comment </button> <Post ref={postRef} /> </> ); }