Reat 中的 useImperativeHandle 鉤子函數(shù)
通過例子說明 ref 的不足
當(dāng)我們需要調(diào)用子組件中的方法時,我們都是考慮使用useRef來調(diào)用子組件的方法,具體的示例代碼如下:
// 父級組件
const UseImperativeHandleDemo: React.FC = () => {
const inputRef = useRef<HTMLInputElement>(null);
return (
<div>
<CustInput ref={inputRef} initVal={"123"} />
<button onClick={() => inputRef.current?.focus()}>獲取焦點(diǎn)</button>
</div>
);
};
// CustInput子組件
const CustInput = React.forwardRef<HTMLInputElement, CustInputProp>(
(
props: CustInputProp,
ref: React.ForwardedRef<HTMLInputElement>
): JSX.Element => {
return <input ref={ref} value={props.initVal} onChange={() => {}} />;
}
);
這個例子中我們只是將一個引用直接傳遞給組件內(nèi)部的單個元素,那是沒有問題的,假如我們需要功能做的更加復(fù)雜一點(diǎn)或者需要自定義引用時,代碼開發(fā)難度可能就會大大提升。
在上述例子中使用 useImperativeHandle 鉤子函數(shù)擴(kuò)展自定義函數(shù)
我們在上述例子的基礎(chǔ)上使用useImperativeHandle鉤子函數(shù)進(jìn)行自定義函數(shù)的擴(kuò)展,擴(kuò)展后我們就可以在父級組件調(diào)用子組件的方法。
使用useImperativeHandle鉤子函數(shù)后我們就可以在子組件中隨意定義方法對外暴露方法。具體的實(shí)例如下:
const CustInput = React.forwardRef<any, CustInputProp>(
(props: CustInputProp, ref: React.ForwardedRef<any>): JSX.Element => {
useImperativeHandle(
ref,
() => {
return { alertHi: () => alert(props.initVal) };
},
[]
);
return <input value={props.initVal} onChange={() => {}} />;
}
);
// 父組件
<button
onClick={() => {
inputRef.current?.alertHi(); // 調(diào)用子組件自定義的方法
}}
>
獲取焦點(diǎn)
</button>;
使用 useImperativeHandle 鉤子函數(shù)控制子組件中的多個元素
在上一小節(jié)我們簡單實(shí)用了useImperativeHandle鉤子函數(shù)進(jìn)行了子組件自定義函數(shù)的擴(kuò)展,在本小節(jié)中,我們可以使用useImperativeHandle鉤子函數(shù)實(shí)現(xiàn)控制子組件中多個元素。
首先我們先看一下我們要實(shí)現(xiàn)的例子,具體界面如下:
[圖片上傳失敗...(image-778d3d-1711673308562)]
在上述的頁面中,我們的業(yè)務(wù)需求是讓上述對應(yīng)的按鈕控制對應(yīng)子組件中對應(yīng)元素的焦點(diǎn),我們可以在父級組件把對應(yīng)的方法編寫好以后傳遞給子組件,但是這樣就會破壞單一職責(zé)原則,所以我們可以使用useImperativeHandle鉤子來實(shí)現(xiàn),具體的代碼如下:
// 父級組件
const [open, setOpen] = useState<boolean>(false)
const modalRef = useRef<any>(null)
<div>
<button onClick={() => setOpen(true)}>open</button>
<button onClick={() => modalRef.current.closeFocus()}>focus close</button>
<button onClick={() => modalRef.current.confirmFocus()}>focus confirm</button>
<button onClick={() => modalRef.current.denyFocus()}>focus deny</button>
<ConfirmationModal
ref={modalRef}
isOpen={open}
onClocse={() => setOpen(false)}
/>
</div>
// 子組件
const ConfirmationModal = React.forwardRef<any, ConfirmationModalProps>(
({ isOpen, onClocse }: ConfirmationModalProps, ref: React.ForwardedRef<any>): JSX.Element => {
const closeRef = useRef<HTMLButtonElement>(null)
const confirmRef = useRef<HTMLButtonElement>(null)
const denyRef = useRef<HTMLButtonElement>(null)
useImperativeHandle(ref, () => {
return {
closeFocus: () => closeRef.current?.focus(),
confirmFocus: () => confirmRef.current?.focus(),
denyFocus: () => denyRef.current?.focus()
}
}, [])
if (!isOpen) return <></>
return (
<div className="modal">
<button className="close-btn" ref={closeRef} onClick={(e) => onClocse()}>×</button>
<div className="modal-header">
<h1>title</h1>
</div>
<div className="modal-body">
do yo confirm?
</div>
<div className="modal-footer">
<button className="confirm-btn" ref={confirmRef} onClick={() => onClocse()}>Yes</button>
<button className="deny-btn" ref={denyRef} onClick={() => onClocse()}>No</button>
</div>
</div>
)
}
)
總結(jié)
通過上述兩個簡單的例子,我們可以看到useImperativeHandle的鉤子函數(shù)主要是簡化我們對子組件的控制,即可以在子組件中實(shí)現(xiàn)自定義函數(shù)和控制子組件中的元素。這就是useImperativeHandle鉤子函數(shù)的作用。