forwardRef מאפשר לרכיב שלך לחשוף צומת DOM לרכיב אב עם ref.

const SomeComponent = forwardRef(render)

הפניה

forwardRef(render)

התקשר ל-forwardRef() כדי לאפשר לרכיב שלך לקבל ר’ ולהעביר אותו לרכיב צאצא:

import { forwardRef } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
// ...
});

ראה דוגמאות נוספות למטה.

פרמטרים

  • render: פונקציית העיבוד של הרכיב שלך. React קורא לפונקציה הזו עם props וref שהרכיב שלך קיבל מהאב שלו. ה-JSX שתחזיר יהיה הפלט של הרכיב שלך.

מחזירה

forwardRef מחזיר רכיב React שאתה יכול לרנדר ב-JSX. בניגוד לרכיבי React המוגדרים כפונקציות רגילות, רכיב המוחזר על ידי forwardRef מסוגל לקבל גם ref תמיכה.

אזהרות

  • במצב קפדני, React תתקשר לפונקציית העיבוד שלך פעמיים ​​על מנת לעזור לך למצוא זיהומים מקריים. זוהי התנהגות לפיתוח בלבד ואינה משפיעה על הייצור. אם פונקציית העיבוד שלך טהורה (כפי שהיא צריכה להיות), זה לא אמור להשפיע על ההיגיון של הרכיב שלך. התוצאה מאחת השיחות תתעלם.

render פונקציה

forwardRef מקבל פונקציית render כארגומנט. React קורא לפונקציה הזו עם props וref:

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

פרמטרים

  • props: ה-props עבר על ידי רכיב האב.

  • ref: התכונה ref הועברה על ידי רכיב האב. ה-ref יכול להיות אובייקט או פונקציה. אם רכיב האב לא עבר שופט, זה יהיה null. עליך להעביר את ref שאתה מקבל לרכיב אחר, או להעביר אותו ל-useImperativeHandle.

מחזירה

forwardRef מחזיר רכיב React שאתה יכול לרנדר ב-JSX. שלא כמו רכיבי React המוגדרים כפונקציות רגילות, הרכיב המוחזר על ידי forwardRef מסוגל לקחת אבזר ref.


שימוש

חשיפת צומת DOM לרכיב האב

כברירת מחדל, הצמתים DOM של כל רכיב הם פרטיים. עם זאת, לפעמים זה useמלא לחשוף צומת DOM להורה - למשל, כדי לאפשר מיקוד שלו. כדי להצטרף, עטוף את הגדרת הרכיב שלך ב-forwardRef():

import { forwardRef } from 'react';

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

תקבל ref בתור הארגומנט השני אחרי props. העבר אותו לצומת DOM שברצונך לחשוף:

import { forwardRef } from 'react';

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

זה מאפשר לרכיב האב Form לגשת אל <input> DOM הצומת שנחשף על ידי MyInput:

function Form() {
const ref = useRef(null);

function handleClick() {
ref.current.focus();
}

return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}

רכיב Form זה מעביר ref ל-MyInput. רכיב MyInput מפנה המפנה לתג הדפדפן <input>. כתוצאה מכך, הרכיב Form יכול לגשת לאותו צומת <input> DOM ולהתקשר אליו focus().

זכור שחשיפת רפר לצומת DOM בתוך הרכיב שלך מקשה על שינוי הרכיבים הפנימיים של הרכיב שלך מאוחר יותר. בדרך כלל תחשוף צמתים DOM מרכיבים ברמה נמוכה הניתנים לשימוש חוזר כמו לחצנים או קלט טקסט, אבל לא תעשה זאת עבור רכיבים ברמת היישום כמו אווטאר או הערה.

Examples of forwarding a ref

Example 1 of 2:
מיקוד קלט טקסט

לחיצה על הכפתור תתמקד בקלט. הרכיב Form מגדיר שופט ומעביר אותו לרכיב MyInput. הרכיב MyInput מעביר את המפנה לדפדפן <input>. זה מאפשר לרכיב Form למקד את ה-<input>.

import { useRef } from 'react';
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <MyInput label="Enter your name:" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}


העברת שופט דרך מספר רכיבים

במקום להעביר ref לצומת DOM, אתה יכול להעביר אותו לרכיב משלך כמו MyInput:

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

אם רכיב ה-MyInput הזה מעביר ר”פ ל-<input> שלו, ר”פ ל-FormField ייתן לך את ה-<input> הזה:

function Form() {
const ref = useRef(null);

function handleClick() {
ref.current.focus();
}

return (
<form>
<FormField label="Enter your name:" ref={ref} isRequired={true} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}

הרכיב Form מגדיר שופט ומעביר אותו לFormField. הרכיב FormField מעביר את הפניה הזו ל-MyInput, שמעביר אותו לצומת <input> DOM של הדפדפן. כך Form ניגש לאותו צומת DOM.

import { useRef } from 'react';
import FormField from './FormField.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    ref.current.focus();
  }

  return (
    <form>
      <FormField label="Enter your name:" ref={ref} isRequired={true} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}


חשיפת ידית ציווי במקום צומת DOM

במקום לחשוף צומת DOM שלם, אתה יכול לחשוף אובייקט מותאם אישית, הנקרא ידית ציווי, עם קבוצה מוגבלת יותר של שיטות. כדי לעשות זאת, תצטרך להגדיר רפר נפרד שיחזיק את הצומת DOM:

const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);

// ...

return <input {...props} ref={inputRef} />;
});

העבר את ה-ref שקיבלת אל useImperativeHandle וציין את הערך שברצונך לחשוף ל-ref:

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 } שלך במקום את הצומת DOM. זה מאפשר לך להגביל את המידע שאתה חושף על הצומת 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>
  );
}

קרא עוד על שימוש בידיות ציוויות.

Pitfall

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

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


פתרון בעיות

הרכיב שלי עטוף ב-forwardRef, אבל ה-ref אליו הוא תמיד null

זה בדרך כלל אומר ששכחת למעשה use את ref שקיבלת.

לדוגמה, הרכיב הזה לא עושה כלום עם ה-ref שלו:

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

כדי לתקן את זה, העבירו את ה-ref לצומת DOM או לרכיב אחר שיכול לקבל ר”פ:

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

ה-ref ל-MyInput יכול להיות גם null אם חלק מהלוגיקה מותנית:

const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
{showInput && <input ref={ref} />}
</label>
);
});

אם showInput הוא false, ה-Ref לא יועבר לשום צומת, ו-Ref ל-MyInput יישאר ריק. זה קל במיוחד לפספס אם התנאי מוסתר בתוך רכיב אחר, כמו Panel בדוגמה זו:

const MyInput = forwardRef(function MyInput({ label, showInput }, ref) {
return (
<label>
{label}
<Panel isExpanded={showInput}>
<input ref={ref} />
</Panel>
</label>
);
});