Kuphuhliso lwangoku lweReact, i-useImperativeHandle hook yindlela enamandla yokwenza ixabiso eliveziweyo lecandelo kwaye linike ulawulo olungaphezulu kwiindlela zalo zangaphakathi kunye neempawu. Ngenxa yoko, ii-APIs zeCandelo elisebenza ngakumbi linokuphucula ukuguquguquka kwemveliso kunye nokugcinwa.
Kwesi siqwenga, ulwazi lweqela loFundo lweNtlalo luntywila kwezona ndlela zibalaseleyo zokusebenzisa i-useImperativeHandle ngokufanelekileyo ukomeleza amacandelo e-React.
I-React ibonelela ngamagwegwe amaninzi (amaxwebhu asemthethweni achaza iigwegwe ezili-17 njengoko kubhaliwe) kulawulo lwelizwe, iziphumo, kunye nokusebenzisana phakathi kwamacandelo.
Phakathi kwazo, i-useImperativeHandle sisixhobo esiluncedo sokwenza ujongano lweprogrammatic (API) yamalungu omntwana, eyongezwe kwi-React ukusuka kwinguqulo ye-16.8.0 ukuya phambili.
useImperativeHandle ikuvumela ukuba wenze okusesikweni okuza kubuyiswa sisijongi esigqithiselwe kwicandelo. Isebenza ngokuhambelana ne-forwardRef, evumela ukuba ireferensi idluliselwe kwicandelo lomntwana.
useImperativeHandle(ref, createHandle, [deps]);
Le hook ivumela ulawulo lwangaphandle lokuziphatha kwecandelo, elinokuba luncedo kwiimeko ezithile, njengokusebenza kunye nethala leencwadi lesithathu, oopopayi abantsokothileyo, okanye amacandelo afuna ukufikelela ngokuthe ngqo kwiindlela. Nangona kunjalo, kufuneka isetyenziswe ngononophelo, njengoko iphula indlela yokubhengeza ye-React.
Masicinge ukuba kufuneka sisebenzise i-DOM yecandelo lomntwana. Nanku umzekelo wendlela yokwenza oku usebenzisa iref.
import React, { forwardRef, useRef } from 'react'; const CustomInput = forwardRef((props, ref) => { // Use forwardRef to pass the ref to the input element return <input ref={ref} {...props} />; }); export default function App() { const inputRef = useRef(); const handleFocus = () => { inputRef.current.focus(); // Directly controlling the input }; const handleClear = () => { inputRef.current.value = ''; // Directly controlling the input value }; return ( <div> <CustomInput ref={inputRef} /> <button onClick={handleFocus}>Focus</button> <button onClick={handleClear}>Clear</button> </div> ); }
Kwaye nantsi indlela enokufezekiswa ngayo usebenzisa useImperativeHandle.
import React, { useImperativeHandle, forwardRef, useRef } from 'react'; const CustomInput = forwardRef((props, ref) => { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); }, clear: () => { inputRef.current.value = ''; }, })); return <input ref={inputRef} {...props} />; }); export default function App() { const inputRef = useRef(); return ( <div> <CustomInput ref={inputRef} /> <button onClick={inputRef.current.focus}>Focus</button> <button onClick={inputRef.current.clear}>Clear</button> </div> ); }
Njengoko kubonisiwe kule mizekelo ingasentla, xa usebenzisa i-useImperativeHandle, icandelo lomntwana linika umzali iseti yeendlela esizichaza ngokwethu.
Ukusebenzisa i-useImperativeHandle kwiimeko eziphambili, njengemizekelo enopopayi, ivumela ukwahlula ukuziphatha okuntsokothileyo ngaphakathi kwecandelo. Oku kwenza icandelo lomzali libe lula kwaye lifundeke ngakumbi, ngakumbi xa usebenza ngoopopayi okanye iilayibrari ezinesandi.
import React, { useRef, useState, useImperativeHandle, forwardRef, memo } from "react"; import { Player } from '@lottiefiles/react-lottie-player' import animation from "./animation.json"; const AnimationWithSound = memo( forwardRef((props, ref) => { const [isAnimating, setIsAnimating] = useState(false); const animationRef = useRef(null); const targetDivRef = useRef(null); useImperativeHandle( ref, () => ({ startAnimation: () => { setIsAnimating(true); animationRef.current?.play() updateStyles("start"); }, stopAnimation: () => { animationRef.current?.stop() updateStyles("stop"); }, }), [] ); const updateStyles = (action) => { if (typeof window === 'undefined' || !targetDivRef.current) return; if (action === "start") { if (targetDivRef.current.classList.contains(styles.stop)) { targetDivRef.current.classList.remove(styles.stop); } targetDivRef.current.classList.add(styles.start); } else if (action === "stop") { if (targetDivRef.current.classList.contains(styles.start)) { targetDivRef.current.classList.remove(styles.start); } targetDivRef.current.classList.add(styles.stop); } }; return ( <div> <Player src={animation} loop={isAnimating} autoplay={false} style={{width: 200, height: 200}} ref={animationRef} /> <div ref={targetDivRef} className="target-div"> This div changes styles </div> </div> ); }) ); export default function App() { const animationRef = useRef(); const handleStart = () => { animationRef.current.startAnimation(); }; const handleStop = () => { animationRef.current.stopAnimation(); }; return ( <div> <h1>Lottie Animation with Sound</h1> <AnimationWithSound ref={animationRef} /> <button onClick={handleStart}>Start Animation</button> <button onClick={handleStop}>Stop Animation</button> </div> ); }
Kulo mzekelo, icandelo lomntwana libuyisela iindlela zokuQala oopopayi kunye nokuyekaAnimation, eziquka ingqiqo entsonkothileyo ngaphakathi kwabo.
Impazamo ayisoloko ibonakala kwangoko. Umzekelo, icandelo labazali linokuthi litshintshe rhoqo iipropu, kwaye unokuhlangabezana nemeko apho indlela yakudala (enedatha endala) iqhubeka isetyenziswa.
Umzekelo wempazamo:
https://use-imperative-handle.levkovich.dev/deps-is-not-correct/wrong
const [count, setCount] = useState(0); const increment = useCallback(() => { console.log("Current count in increment:", count); // Shows old value setCount(count + 1); // Are using the old value of count }, [count]); useImperativeHandle( ref, () => ({ increment, // Link to the old function is used }), [] // Array of dependencies do not include increment function );
Indlela elungileyo:
const [count, setCount] = useState(0); useImperativeHandle( ref, () => ({ increment, }), [increment] // Array of dependencies include increment function );
2. Akukho luhlu lokuxhomekeka
Ukuba uluhlu oluxhomekeke kuluhlu alubonelelwanga, i-React iyakuthatha into ekwi-useImperativeHandle kufuneka yenziwe kwakhona kuyo yonke i-render. Oku kunokubangela imiba ebalulekileyo yokusebenza, ngakumbi ukuba izibalo "ezinzima" zenziwa ngaphakathi kwikhonkco.
Umzekelo wempazamo:
useImperativeHandle(ref, () => { // There is might be a difficult task console.log("useImperativeHandle calculated again"); return { focus: () => {} } }); // Array of dependencies is missing
Indlela elungileyo:
useImperativeHandle(ref, () => { // There is might be a difficult task console.log("useImperativeHandle calculated again"); return { focus: () => {} } }, []); // Array of dependencies is correct
Ukuguqulwa ngokuthe ngqo kwe-ref.current kuphazamisa ukuziphatha kwe-React. Ukuba i-React izama ukuhlaziya iref, oko kunokukhokelela kungquzulwano okanye iimpazamo ezingalindelekanga.
Umzekelo wempazamo:
useImperativeHandle(ref, () => { // ref is mutated directly ref.current = { customMethod: () => console.log("Error") }; });
Indlela elungileyo:
useImperativeHandle(ref, () => ({ customMethod: () => console.log("Correct"), }));
Iindlela zokufowuna ezibonelelwe ngokusebenzisa i-UseImperativeHandle ukusuka kwi-useEffect okanye abaphathi besiganeko, becinga ukuba i-ref sele ikhona, inokukhokelela kwiimpazamo - soloko ujonge okwangoku ngaphambi kokubiza iindlela zayo.
Umzekelo wempazamo:
const increment = useCallback(() => { childRef.current.increment(); }, [])
Indlela elungileyo:
const increment = useCallback(() => { if (childRef.current?.increment) { childRef.current.increment() } }, [])
Ukuba useImperativeHandle ibuyisela iindlela ezitshintsha iimeko ngaxeshanye (umzekelo, ukuqala uphiliso kunye nezimbo zokuguqula ngaxeshanye), kunokubangela "umsantsa" phakathi kwemo yokubonwayo kunye nengqiqo yangaphakathi. Qinisekisa ukuhambelana phakathi kwelizwe kunye nokuziphatha okubonakalayo, umzekelo, ngokusebenzisa iziphumo (useEffect).
Umzekelo wempazamo:
useImperativeHandle(ref, () => ({ startAnimation: () => { setState("running"); // Animation starts before the state changes lottieRef.current.play(); }, stopAnimation: () => { setState("stopped"); // Animation stops before the state changes lottieRef.current.stop(); }, }));
Indlela elungileyo:
useEffect(() => { if (state === "running" && lottieRef.current) { lottieRef.current.play(); } else if (state === "stopped" && lottieRef.current) { lottieRef.current.stop(); } }, [state]); // Triggered when the state changes useImperativeHandle( ref, () => ({ startAnimation: () => { setState("running"); }, stopAnimation: () => { setState("stopped"); }, }), [] );
Ukusebenzisa i-useImperativeHandle kuyathetheleleka kwezi meko zilandelayo:
Ukulawula ukuziphatha kwecandelo lomntwana: Umzekelo, ukubonelela ngogqaliselo okanye indlela yokusetha ngokutsha yecandelo legalelo elintsonkothileyo.
Ukufihla iinkcukacha zokuphunyezwa: Icandelo lomzali lifumana kuphela iindlela elizidingayo, hayi yonke into yokukhangela.
Ngaphambi kokusebenzisa i-useImperativeHandle, zibuze le mibuzo:
Ngokufunda i hook ye-useImperativeHandle, abaphuhlisi beReact banokudala amacandelo asebenzayo kunye nokugcinwa ngokukhetha ngokukhetha iindlela. Ubuchule obubekwe liqela leQela loFundo lweNtlalo lunokunceda abaphuhlisi baphucule ukuguquguquka kwabo, balungelelanise icandelo labo le-APIs, kwaye baphucule ukusebenza ngokubanzi kweapp.
Ibhalwe nguSergey Levkovich, uNjineli oPhezulu weSoftware kwiQela loFundo lweNtlalo