useImperativeHandle

useImperativeHandle הוא React Hook שמאפשר להתאים אישית את ה-handle שנחשף כ-ref.

useImperativeHandle(ref, createHandle, dependencies?)

Reference

useImperativeHandle(ref, createHandle, dependencies?)

קראו ל-useImperativeHandle ברמה העליונה של הקומפוננטה כדי להתאים אישית את ref handle שהיא חושפת:

import { forwardRef, useImperativeHandle } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... your methods ...
};
}, []);
// ...

ראו דוגמאות נוספות בהמשך.

Parameters

  • ref: ה-ref שקיבלתם כארגומנט השני מתוך forwardRef render function.

  • createHandle: פונקציה שלא מקבלת ארגומנטים ומחזירה את ref handle שתרצו לחשוף. ה-handle הזה יכול להיות מכל סוג. בדרך כלל תחזירו אובייקט עם המתודות שתרצו לחשוף.

  • אופציונלי dependencies: רשימה של כל הערכים הריאקטיביים שמופנים בתוך קוד ה-createHandle. ערכים ריאקטיביים כוללים props, state וכל המשתנים והפונקציות שמוגדרים ישירות בתוך גוף הקומפוננטה. אם ה-linter שלכם מוגדר ל-React, הוא יוודא שכל ערך ריאקטיבי מצוין נכון כ-dependency. רשימת ה-dependencies חייבת להיות במספר פריטים קבוע ולהיכתב inline כמו [dep1, dep2, dep3]. React תשווה כל dependency לערך הקודם שלו באמצעות Object.is. אם re-render גרם לשינוי ב-dependency כלשהו, או אם השמטתם את הארגומנט הזה, פונקציית createHandle תרוץ מחדש, וה-handle החדש שייווצר יוקצה ל-ref.

Returns

useImperativeHandle מחזיר undefined.


שימוש

חשיפת ref handle מותאם לקומפוננטת ההורה

כברירת מחדל, קומפוננטות לא חושפות את ה-DOM nodes שלהן לקומפוננטות הורה. למשל, אם אתם רוצים שלקומפוננטת ההורה של MyInput תהיה גישה ל-<input> DOM node, צריך לבצע opt-in עם forwardRef:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} ref={ref} />;
});

עם הקוד למעלה, ref ל-MyInput יקבל את <input> DOM node. אבל אפשר גם לחשוף ערך מותאם אישית במקום. כדי להתאים את ה-handle שנחשף, קראו ל-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 node, אלא רק שתי מתודות: focus ו-scrollIntoView. כדי לעשות זאת, שמרו את ה-DOM האמיתי של הדפדפן ב-ref נפרד. אחר כך השתמשו ב-useImperativeHandle כדי לחשוף handle שמכיל רק את המתודות שאתם רוצים שההורה יוכל לקרוא להן:

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} />;
});

עכשיו, אם קומפוננטת ההורה מקבלת ref ל-MyInput, היא תוכל לקרוא למתודות focus ו-scrollIntoView. עם זאת, לא תהיה לה גישה מלאה ל-<input> DOM node עצמו.

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>
  );
}


חשיפת מתודות imperative משלכם

המתודות שאתם חושפים דרך imperative handle לא חייבות להתאים בדיוק למתודות DOM. לדוגמה, קומפוננטת Post הזו חושפת מתודה בשם scrollAndFocusAddComment דרך imperative handle. זה מאפשר ל-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} />
    </>
  );
}

Pitfall

אל תשתמשו ב-refs מעבר לנדרש. כדאי להשתמש ב-refs רק להתנהגויות imperative שלא ניתן לבטא כ-props: למשל גלילה ל-node, פוקוס ל-node, הפעלת אנימציה, בחירת טקסט, וכן הלאה.

אם אפשר לבטא משהו כ-prop, לא כדאי להשתמש ב-ref. לדוגמה, במקום לחשוף imperative handle כמו { open, close } מתוך קומפוננטת Modal, עדיף לקבל isOpen כ-prop כמו <Modal isOpen={isOpen} />. Effects יכולות לעזור לחשוף התנהגויות imperative דרך props.