useImperativeHandle Hook
useImperativeHandle Hook — կոմպոնենտների վերահսկում ref-ի միջոցով
React-ում սովորաբար տվյալները փոխանցվում են վերևից ներքև՝ props-երի միջոցով։ Սակայն երբեմն անհրաժեշտ է, որ ծնող կոմպոնենտը կարողանա ուղղակիորեն կանչել երեխայի մեթոդներ կամ ֆունկցիաներ։ Օրինակ՝ բացել կամ փակել modal, scroll անել list-ը, կամ reset անել input-ի արժեքը։ Այս դեպքում React-ը տրամադրում է useImperativeHandle hook-ը՝ աշխատելու համար forwardRef-ի հետ։
useImperativeHandle(ref, createHandle, deps)
հրամայում է React-ին, թե ինչ պետք է տեսնի ծնողը, երբ օգտագործում է ref-ը տվյալ կոմպոնենտի վրա։
forwardRef-ով։Ստեղծենք կոմպոնենտ, որը ներսում ունի input և իր սեփական focus մեթոդ։ Ծնող կոմպոնենտը կկարողանա կանչել այդ մեթոդը ref-ի միջոցով։
// CustomInput.js
import React, { useRef, forwardRef, useImperativeHandle } from 'react';
const CustomInput = forwardRef((props, ref) => {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
clear: () => {
inputRef.current.value = '';
}
}));
return (
<input
ref={inputRef}
type="text"
placeholder="Գրիր ինչ-որ բան..."
/>
);
});
export default CustomInput;
// App.js
import React, { useRef } from 'react';
import CustomInput from './CustomInput';
export default function App() {
const inputRef = useRef();
return (
<div>
<CustomInput ref={inputRef} />
<br />
<button onClick={() => inputRef.current.focus()}>Focus</button>
<button onClick={() => inputRef.current.clear()}>Clear</button>
</div>
);
}
Այստեղ ծնողը (App) կարողանում է կանչել երեխայի (CustomInput) մեթոդները՝
focus() և clear(), առանց props փոխանցելու։
Այսպիսով, մենք ստեղծեցինք փոքր “public API” երեխայի համար։
Առանց useImperativeHandle, React-ը ref-ի միջոցով ծնողին կտար DOM node-ը (օր. input-ի հղումը)։ Բայց շատ դեպքերում դա բավարար չէ։ useImperativeHandle-ի միջոցով մենք կարող ենք տալ ծնողին միայն այն մեթոդները կամ տվյալները, որոնք ուզում ենք վերահսկել։
Այս մոտեցումը հատկապես օգտակար է՝ երբ ցանկանում ես սահմանափակել ծնողի հասանելիությունը ներքին լոգիկային։
Սա պրոֆեսիոնալ օրինակ է, որտեղ ծնողը բացում և փակում է modal-ը՝ ref-ի միջոցով։
// Modal.js
import React, { useState, forwardRef, useImperativeHandle } from 'react';
const Modal = forwardRef((props, ref) => {
const [isOpen, setIsOpen] = useState(false);
useImperativeHandle(ref, () => ({
open: () => setIsOpen(true),
close: () => setIsOpen(false)
}));
if (!isOpen) return null;
return (
<div style={{
position: 'fixed',
top: 0, left: 0, right: 0, bottom: 0,
background: 'rgba(0,0,0,0.5)',
display: 'flex', justifyContent: 'center', alignItems: 'center'
}}>
<div style={{ background: 'white', padding: '20px', borderRadius: '8px' }}>
<h3>Modal պատուհան</h3>
<button onClick={() => setIsOpen(false)}>Փակել</button>
</div>
</div>
);
});
export default Modal;
// App.js
import React, { useRef } from 'react';
import Modal from './Modal';
export default function App() {
const modalRef = useRef();
return (
<div>
<button onClick={() => modalRef.current.open()}>Բացել Modal</button>
<Modal ref={modalRef} />
</div>
);
}
Այս օրինակում ծնողը լիովին վերահսկում է երեխայի վարքը՝ առանց props-երի։ Այն շատ նման է imperatively “openModal()” կամ “closeModal()” ֆունկցիաների գործելաոճին։
Երբեմն ցանկանում ես, որ ծնողը չկարողանա հասնել բոլոր ներքին մեթոդներին։ useImperativeHandle-ը թույլ է տալիս “թաքցնել” մնացածը։
useImperativeHandle(ref, () => ({
open: () => setVisible(true),
close: () => setVisible(false)
}), []); // միայն երկու մեթոդ հասանելի ծնողին
Այս ձևով ծնողը չի կարող փոխել state-ը կամ DOM-ը ուղղակիորեն։
Գրիր կոմպոնենտ, որը․