useRef הוא React Hook המאפשר לך להתייחס לערך שאינו נחוץ לעיבוד.
const ref = useRef(initialValue)הפניה
useRef(initialValue)
התקשר ל-useRef ברמה העליונה של הרכיב שלך כדי להכריז על ref.
import { useRef } from 'react';
function MyComponent() {
const intervalRef = useRef(0);
const inputRef = useRef(null);
// ...פרמטרים
initialValue: הערך שאתה רוצה שמאפייןcurrentשל אובייקט ref יהיה בהתחלה. זה יכול להיות ערך מכל סוג שהוא. טענה זו מתעלמת לאחר העיבוד הראשוני.
מחזירה
useRef מחזיר אובייקט עם מאפיין יחיד:
current: בתחילה, הוא מוגדר ל-initialValueשעברת. מאוחר יותר תוכל להגדיר אותו למשהו אחר. אם תעביר את אובייקט ref ל-React כתכונהrefלצומת JSX, React יגדיר את המאפייןcurrentשלו.
בעיבודים הבאים, useRef יחזיר את אותו אובייקט.
אזהרות
- אתה יכול לשנות את המאפיין
ref.current. שלא כמו state, זה ניתן לשינוי. עם זאת, אם הוא מכיל אובייקט שהוא used לעיבוד (לדוגמה, חלק מה-state שלך), אז אל תעשה מוטציה לאובייקט זה. - כאשר אתה משנה את המאפיין
ref.current, React אינו מעבד מחדש את הרכיב שלך. React לא מודע מתי אתה משנה את זה מכיוון שuse רפר הוא אובייקט JavaScript רגיל. - אל תכתוב או קרא
ref.currentבמהלך העיבוד, למעט אתחול. זה הופך את התנהגות הרכיב שלך לבלתי צפויה. - במצב קפדני, React תתקשר לפונקציית הרכיב שלך פעמיים כדי לעזור לך למצוא זיהומים מקריים. זוהי התנהגות לפיתוח בלבד ואינה משפיעה על הייצור. כל אובייקט ref ייווצר פעמיים, אך אחת מהגרסאות תימחק. אם פונקציית הרכיב שלך טהורה (כפי שהיא צריכה להיות), זה לא אמור להשפיע על ההתנהגות.
שימוש
הפניית ערך עם ref
התקשר ל-useRef ברמה העליונה של הרכיב שלך כדי להכריז על אחד או יותר refs.
import { useRef } from 'react';
function Stopwatch() {
const intervalRef = useRef(0);
// ...useRef מחזירה ref object עם current מאפיין בודד שהוגדר תחילה לערך ההתחלתי שסיפקת.
בעיבודים הבאים, useRef יחזיר את אותו אובייקט. אתה יכול לשנות את המאפיין current שלו כדי לאחסן מידע ולקרוא אותו מאוחר יותר. זה עשוי להזכיר לך את state, אבל יש הבדל חשוב.
החלפת רפ’ לא מפעילה עיבוד מחדש. פירוש הדבר שהשו”פים מושלמים לאחסון מידע שאינו משפיע על הפלט החזותי של הרכיב שלך. לדוגמה, אם אתה צריך לאחסן מזהה מרווח ולאחזר אותו מאוחר יותר, אתה יכול לשים אותו ב-ref. כדי לעדכן את הערך בתוך ה-ref, עליך לשנות באופן ידני את current המאפיין שלו:
function handleStartClick() {
const intervalId = setInterval(() => {
// ...
}, 1000);
intervalRef.current = intervalId;
}מאוחר יותר, תוכל לקרוא את מזהה המרווח הזה מהשופט כדי שתוכל להתקשר לנקות את המרווח הזה:
function handleStopClick() {
const intervalId = intervalRef.current;
clearInterval(intervalId);
}על ידי שימוש ב-Ref, אתה מבטיח כי:
- ניתן לאחסן מידע בין רינדור מחדש (בניגוד למשתנים רגילים, שמתאפסים בכל עיבוד).
- שינוי זה לא מפעיל רינדור מחדש (בניגוד למשתנים state, שמפעילים עיבוד מחדש).
- המידע הוא מקומי לכל עותק של הרכיב שלך (בניגוד למשתנים שבחוץ, המשותפים).
שינוי רפ אינו מפעיל רינדור מחדש, כך ששו”פים אינם מתאימים לאחסון מידע שברצונך להציג על המסך. השתמש ב-state עבור זה במקום זאת. קרא עוד על בחירה בין useRef ל-useState.
Example 1 of 2: מונה קליקים
רכיב זה use הוא רשופט כדי לעקוב אחר מספר הפעמים שנלחץ על הכפתור. שימו לב שזה בסדר לכתוב use ר”פ במקום state כאן כי use ספירת הקליקים נקראת ונכתבת רק במטפל באירועים.
import { useRef } from 'react'; export default function Counter() { let ref = useRef(0); function handleClick() { ref.current = ref.current + 1; alert('You clicked ' + ref.current + ' times!'); } return ( <button onClick={handleClick}> Click me! </button> ); }
אם תראה {ref.current} ב-JSX, המספר לא יתעדכן בלחיצה. זוהי מכיוון שהגדרת ref.current לא מפעילה עיבוד מחדש. מידע שהוא used לעיבוד צריך להיות state במקום זאת.
מניפולציה של DOM עם שו”ת
זה נפוץ במיוחד ל-use שופט כדי לתפעל את DOM. React יש תמיכה מובנית לכך.
ראשית, הכריז על ref object עם ערך התחלתי של null:
import { useRef } from 'react';
function MyComponent() {
const inputRef = useRef(null);
// ...לאחר מכן העבר את אובייקט ה-ref שלך כתכונה ref ל-JSX של הצומת DOM שברצונך לתפעל:
// ...
return <input ref={inputRef} />;לאחר React יוצר את הצומת DOM ומעלה אותו על המסך, React יגדיר את current המאפיין של אובייקט ה-ref שלך לצומת DOM זה. עכשיו אתה יכול לגשת לצומת DOM של <input> ולשיטות קריאה כמו focus():
function handleClick() {
inputRef.current.focus();
}React יחזיר את המאפיין current ל-null כאשר הצומת יוסר מהמסך.
קרא עוד על מניפולציה של DOM עם refs.
Example 1 of 4: מיקוד קלט טקסט
בדוגמה זו, לחיצה על הכפתור תתמקד בקלט:
import { useRef } from 'react'; export default function Form() { const inputRef = useRef(null); function handleClick() { inputRef.current.focus(); } return ( <> <input ref={inputRef} /> <button onClick={handleClick}> Focus the input </button> </> ); }
הימנעות מיצירה מחדש של תוכן השופט
React שומר את ערך ה-ref הראשוני פעם אחת ומתעלם ממנו בעיבודים הבאים.
function Video() {
const playerRef = useRef(new VideoPlayer());
// ...למרות שהתוצאה של new VideoPlayer() היא רק used עבור העיבוד הראשוני, אתה עדיין קורא לפונקציה הזו בכל עיבוד. זה יכול להיות בזבזני אם זה יוצר חפצים יקרים.
כדי לפתור את זה, אתה יכול לאתחל את השופט כך במקום זאת:
function Video() {
const playerRef = useRef(null);
if (playerRef.current === null) {
playerRef.current = new VideoPlayer();
}
// ...בדרך כלל, כתיבה או קריאה של ref.current במהלך העיבוד אינם מותרים. עם זאת, זה בסדר במקרה הזה כי התוצאה היא תמיד זהה, והתנאי מופעלת רק במהלך האתחול, כך שהוא ניתן לחיזוי מלא.
Deep Dive
אם אתה use בודק סוגים ולא רוצה לבדוק תמיד את null, אתה יכול לנסות דפוס כזה במקום זאת:
function Video() {
const playerRef = useRef(null);
function getPlayer() {
if (playerRef.current !== null) {
return playerRef.current;
}
const player = new VideoPlayer();
playerRef.current = player;
return player;
}
// ...כאן, ה-playerRef עצמו ניתן ל- null. עם זאת, אתה אמור להיות מסוגל לשכנע את בודק הסוג שלך שאין מקרה שבו getPlayer() מחזיר null. ואז use getPlayer() במטפלי האירועים שלך.
פתרון בעיות
אני לא יכול לקבל רפרנט לרכיב מותאם אישית
אם תנסה להעביר ref לרכיב משלך כך:
const inputRef = useRef(null);
return <MyInput ref={inputRef} />;ייתכן שתקבל שגיאה בקונסולה:
כברירת מחדל, הרכיבים שלך אינם חושפים רפרנסים לצמתים DOM שבתוכם.
כדי לתקן זאת, מצא את הרכיב שאליו ברצונך לקבל רפרנט:
export default function MyInput({ value, onChange }) {
return (
<input
value={value}
onChange={onChange}
/>
);
}ואז עטפו אותו ב-forwardRef כך:
import { forwardRef } from 'react';
const MyInput = forwardRef(({ value, onChange }, ref) => {
return (
<input
value={value}
onChange={onChange}
ref={ref}
/>
);
});
export default MyInput;אז רכיב האב יכול לקבל ר”פ אליו.
קרא עוד על גישה לצמתי DOM של רכיב אחר.