הוקים ב-React הם פונקציות ששמן מתחיל ב-use ומאפשרות לקומפוננטת פונקציה להשתמש ביכולות של React: useState כדי לזכור ערך, useEffect כדי להריץ קוד אחרי הרינדור, useRef כדי להחזיק צומת DOM, useContext כדי לקרוא נתונים משותפים. קוראים להם בראש הקומפוננטה, ו-React שומרת את הערכים שלהם בין רינדורים.
ארבעה הוקים עובדים כאן יחד. useState שומר את הטקסט, useRef מצביע על השדה כדי שהכפתור יוכל לתת לו פוקוס, useMemo שומר את הרשימה המסוננת עד שהשאילתה משתנה, ו-useEffect רושם אחרי כל רינדור שבו השאילתה השתנתה. הקלידו an ושימו לב ל-Console: שורה אחת לכל הקשה, אחרי שהרשימה מתעדכנת.
למה הוקים קיימים
לפני React 16.8, קומפוננטה שהייתה צריכה state או קוד מחזור חיים הייתה חייבת להיות class. הלוגיקה של פיצ'ר אחד התפצלה בין componentDidMount, componentDidUpdate ו-componentWillUnmount, ושיתוף שלה בין קומפוננטות דרש mixins (שאף פעם לא עבדו עם תחביר class), higher order components או render props, וכולם עטפו את העץ בשכבות נוספות.
// The class way: one feature, three methods
class Clock extends React.Component {
state = { now: new Date() };
componentDidMount() {
this.id = setInterval(() => this.setState({ now: new Date() }), 1000);
}
componentWillUnmount() {
clearInterval(this.id);
}
render() {
return <p>{this.state.now.toLocaleTimeString()}</p>;
}
}
עם הוקים אותו פיצ'ר חי במקום אחד: האפקט מפעיל את הטיימר וה-cleanup שלו עוצר אותו.
הסתירו את השעון וה-Console מדפיס timer stopped: React הריצה את ה-cleanup כש-Clock עזב את המסך. הציגו אותו שוב וטיימר חדש מתחיל. קומפוננטות class עדיין עובדות ב-React 19, אבל קוד חדש משתמש בהוקים.
כל ההוקים המובנים
React 19.2 מקבצת את ההוקים שלה לפי מה שהם נותנים לקומפוננטה. בשתי הקבוצות הראשונות תשתמשו כל יום, ובשאר כשבעיה מסוימת דורשת אותן.
| הוק | מה הוא נותן | דף |
|---|---|---|
useState | ערך ששורד רינדורים ו-setter שמרנדר שוב | useState |
useReducer | state שמתעדכן על ידי פונקציית reducer ו-actions שנשלחים | useReducer |
useContext | ערך שמסופק על ידי הורה, בלי להעביר props | useContext |
useRef | קופסה ניתנת לשינוי ששורדת רינדורים, לעיתים קרובות צומת DOM | useRef |
useImperativeHandle | בוחר מה הורה רואה דרך ה-ref שלכם | forwardRef |
useEffect | קוד שרץ בדרך כלל אחרי הציור: טיימרים, מנויים, טעינת נתונים | useEffect |
useLayoutEffect | קוד שרץ אחרי עדכון ה-DOM אבל לפני הציור | useLayoutEffect |
useInsertionEffect | רץ לפני layout effects, בשביל ספריות CSS-in-JS | |
useEffectEvent | פונקציה שאפקט יכול לקרוא לה ושתמיד רואה את ה-props וה-state העדכניים | useEffect |
useMemo | שומר ב-cache ערך מחושב בין רינדורים | useMemo |
useCallback | שומר ב-cache פונקציה בין רינדורים | useCallback |
useTransition | מסמן עדכון כלא דחוף ואומר לכם מתי הוא ממתין | useTransition |
useDeferredValue | עותק של ערך שמפגר מאחור בזמן רינדורים כבדים | useDeferredValue |
useId | מזהה ייחודי שתואם בשרת ובלקוח | useId |
useSyncExternalStore | נרשם ל-store שחי מחוץ ל-React | useSyncExternalStore |
useDebugValue | תווית להוק מותאם ב-React DevTools | |
use | קורא promise או קונטקסט, ויכול לשבת בתוך תנאי | use |
useActionState | state ש-form action מעדכן, עם דגל pending | useActionState |
useOptimistic | מציג את התוצאה הצפויה לפני שהשרת עונה | useOptimistic |
useFormStatus | מצב ה-pending של הטופס שמעל (מ-react-dom) |
use, useActionState, useOptimistic ו-useFormStatus הגיעו עם React 19, ו-useEffectEvent נהיה יציב ב-19.2. כל שאר ההוקים ברשימה עובדים גם ב-React 18.
state מרנדר, refs לא
לא כל הוק מפעיל רינדור. useState ו-useReducer כן: שנו את הערך שלהם ו-React מציירת את הקומפוננטה שוב. useRef נותן לכם אובייקט שאפשר לשנות את שדה ה-current שלו בחופשיות, ו-React אף פעם לא מרנדרת מחדש בגללו. זה הופך אותו למקום הנכון למזהה טיימר, לערך קודם, או לספירה שהמסך לא מציג.
useReducer מחזיק את העגלה ו-useState מחזיק את ההערה; שניהם גורמים לרינדור כשהם משתנים, והאפקט רושם שורה אחת לכל רינדור. האפקט גם משנה את commits.current, ובכל זאת השינוי הזה אף פעם לא גורם לרינדור משלו, ולכן הלוג לא נכנס ללולאה. הספירה מתעדכנת באפקט ולא בגוף הקומפוננטה כי הגוף לא אמור לשנות שום דבר בזמן שהוא מתרנדר.
כללי ההוקים
כל הוק עוקב אחרי שני כללים:
- קראו להוקים ברמה העליונה של הקומפוננטה, אף פעם לא בתוך תנאי, לולאה או פונקציה מקוננת.
- קראו להוקים רק מקומפוננטות פונקציה או מהוקים מותאמים משלכם.
React לא מכירה הוקים לפי שם. היא מכירה אותם לפי הסדר שבו קוראים להם, ומצפה שהסדר הזה יהיה זהה בכל רינדור. הוק בתוך if היה מזיז כל הוק שאחריו. הדף על כללי ההוקים מראה מה נשבר ואיך מתקנים. use הוא החריג היחיד: מותר לקרוא לו בתוך תנאי.
ההוק המותאם הראשון שלכם
כששתי קומפוננטות צריכות את אותה לוגיקה עם state, העבירו אותה לפונקציה ששמה מתחיל ב-use. הפונקציה הזו יכולה לקרוא לכל הוק אחר. כל קומפוננטה שקוראת לה מקבלת state משלה.
שני המונים מריצים את אותו הוק, אבל לחיצה על אחד לא נוגעת בשני: הוק מותאם משתף לוגיקה, לא state. הוסיפו פונקציית decrement ל-useCounter וכפתור שקורא לה, ושני המונים מקבלים אותה בבת אחת. דפוסים נוספים (useToggle, useDebounce, useLocalStorage) נמצאים בדף על הוקים מותאמים אישית.
לאיזה הוק לפנות
- המסך צריך להשתנות כשערך משתנה:
useState, אוuseReducerכשהרבה אירועים מעדכנים את אותו state. - צריך לדבר עם משהו מחוץ ל-React (טיימר, מנוי, בקשה):
useEffect. - צריך צומת DOM או ערך שהמסך לא מציג:
useRef. - הרבה קומפוננטות עמוק בעץ צריכות את אותו ערך:
useContext. - רינדור איטי בגלל חישוב אחד או בגלל שילד עם memo מתרנדר מחדש:
useMemoו-useCallback. React Compiler יכול להוסיף את ה-memoization הזה בשבילכם, אבל כתיבה ידנית עדיין עובדת ועדיין נפוצה. - ההקלדה מרגישה איטית כי העדכון שמאחוריה כבד:
useTransitionאוuseDeferredValue.
שאלות נפוצות
מה הם הוקים ב-React?
הוקים הם פונקציות ששמן מתחיל ב-use ומאפשרות לקומפוננטת פונקציה להשתמש ביכולות של React: useState בשביל state, useEffect בשביל תופעות לוואי, useContext בשביל קונטקסט, useRef בשביל ערכים ששורדים רינדורים בלי לגרום לרינדור, ועוד.
למה הוקים נוספו ל-React?
לפני ההוקים (React 16.8), state ומתודות מחזור חיים היו קיימים רק בקומפוננטות class, ושיתוף לוגיקה עם state דרש mixins, higher order components או render props. הוקים שמים את הלוגיקה הזו בפונקציות רגילות שאפשר לקרוא להן מכל קומפוננטת פונקציה ולשתף כהוקים מותאמים אישית.
כמה הוקים יש ב-React?
React 19.2 מגיעה עם בערך עשרים הוקים מובנים בחבילה react, ועוד useFormStatus ב-react-dom. רוב האפליקציות משתמשות ביומיום בקומץ מהם: useState, useEffect, useRef, useContext, useMemo ו-useCallback.
אפשר להשתמש בהוקים בקומפוננטות class?
לא. הוקים עובדים רק בתוך קומפוננטות פונקציה והוקים אחרים. עדיין אפשר לרנדר קומפוננטת class ליד קומפוננטות פונקציה, ו-class יכולה לרנדר קומפוננטת פונקציה שמשתמשת בהוקים.
מה זה הוק מותאם אישית?
פונקציה משלכם ששמה מתחיל ב-use ושקוראת להוקים אחרים. היא מאפשרת לכמה קומפוננטות להשתמש שוב באותה לוגיקה עם state, ובכל זאת כל קומפוננטה שקוראת לה מקבלת state נפרד משלה.