Component היא המחלקה הבסיסית עבור רכיבי React המוגדרים כ-JavaScript מחלקות. רכיבי מחלקה עדיין נתמכים על ידי React, אך אנו לא ממליצים להשתמש בהם בקוד חדש.
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}- הפניה
Componentcontextpropsrefsstateconstructor(props)componentDidCatch(error, info)componentDidMount()componentDidUpdate(prevProps, prevState, snapshot?)componentWillMount()componentWillReceiveProps(nextProps)componentWillUpdate(nextProps, nextState)componentWillUnmount()forceUpdate(callback?)getChildContext()getSnapshotBeforeUpdate(prevProps, prevState)render()setState(nextState, callback?)shouldComponentUpdate(nextProps, nextState, nextContext)UNSAFE_componentWillMount()UNSAFE_componentWillReceiveProps(nextProps, nextContext)UNSAFE_componentWillUpdate(nextProps, nextState)static childContextTypesstatic contextTypesstatic contextTypestatic defaultPropsstatic propTypesstatic getDerivedStateFromError(error)static getDerivedStateFromProps(props, state)
- שימוש
- חלופות
הפניה
Component
כדי להגדיר רכיב React כמחלקה, הרחב את המחלקה המובנית Component והגדר שיטה render:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}נדרשת רק שיטת render, שיטות אחרות הן אופציונליות.
context
ה-הקשר של רכיב מחלקה זמין בתור this.context. זה זמין רק אם אתה מציין איזה הקשר אתה רוצה לקבל באמצעות static contextType (מודרני) או static contextTypes (הוצא משימוש).
רכיב מחלקה יכול לקרוא רק הקשר אחד בכל פעם.
class Button extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}props
ה-props שהועברו לרכיב מחלקה זמינים בתור this.props.
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
<Greeting name="Taylor" />refs
מאפשר לך לגשת למחרוזת מדור קודם עבור רכיב זה.
state
ה-state של רכיב מחלקה זמין בתור this.state. השדה state חייב להיות אובייקט. אל תשנה את ה-state ישירות. אם ברצונך לשנות את ה-state, התקשר ל-setState עם ה-state החדש.
class Counter extends Component {
state = {
age: 42,
};
handleAgeChange = () => {
this.setState({
age: this.state.age + 1
});
};
render() {
return (
<>
<button onClick={this.handleAgeChange}>
Increment age
</button>
<p>You are {this.state.age}.</p>
</>
);
}
}constructor(props)
קונסטרוקטור פועל לפני שרכיב המחלקה שלך מועלה (מתווסף למסך). בדרך כלל, בנאי הוא רק used לשתי מטרות ב-React. הוא מאפשר לך להכריז על state ו-bind שיטות המחלקה שלך למופע המחלקה:
class Counter extends Component {
constructor(props) {
super(props);
this.state = { counter: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
// ...
}אם אתה use תחביר JavaScript מודרני, לעתים נדירות יש צורך בבנאים. במקום זאת, אתה יכול לשכתב את הקוד הזה למעלה באמצעות תחביר שדה הכיתה הציבורי שנתמך הן על ידי דפדפנים מודרניים והן על ידי כלים כמו Babel:
class Counter extends Component {
state = { counter: 0 };
handleClick = () => {
// ...
}בנאי לא אמור להכיל תופעות לוואי או מנויים.
פרמטרים
props: ה-props הראשוני של הרכיב.
מחזירה
constructor לא אמור להחזיר כלום.
אזהרות
-
אל תפעיל תופעות לוואי או מנויים בבנאי. במקום זאת, use
componentDidMountעבור זה. -
בתוך קונסטרוקטור, אתה צריך לקרוא
super(props)לפני כל statement אחר. אם לא תעשה זאת,this.propsיהיהundefinedבזמן שהקונסטרוקטור פועל, מה שיכול להיות מבלבל ו-cause באגים. -
Constructor הוא המקום היחיד שבו אתה יכול להקצות את
this.stateישירות. בכל שאר השיטות, אתה צריך usethis.setState()במקום זאת. אל תקרא ל-setStateבקונסטרוקטור. -
כאשר אתה use עיבוד שרת, הבנאי יפעל גם על השרת, ואחריו השיטה
render. עם זאת, שיטות מחזור חיים כמוcomponentDidMountאוcomponentWillUnmountלא יפעלו בשרת. -
כאשר מצב קפדני מופעל, React יתקשר ל-
constructorפעמיים בפיתוח ולאחר מכן יזרוק את אחד מהמופעים. זה עוזר לך להבחין בתופעות הלוואי המקריות שיש להעביר מה-constructor.
componentDidCatch(error, info)
אם תגדיר componentDidCatch, React יקרא לזה כאשר רכיב צאצא כלשהו (כולל ילדים רחוקים) זורק שגיאה במהלך העיבוד. זה מאפשר לך לרשום את השגיאה לשירות דיווח שגיאות בייצור.
בדרך כלל, זה used יחד עם static getDerivedStateFromError המאפשר לך לעדכן את state בתגובה לשגיאה ולהציג הודעת שגיאה ל-user. רכיב עם שיטות אלה נקרא גבול שגיאה.
פרמטרים
-
error: השגיאה שנזרקה. בפועל, זה בדרך כלל יהיה מופע שלErrorאבל זה לא מובטח כיuse JavaScript מאפשרthrowכל ערך, כולל מחרוזות או אפילוnull. -
info: אובייקט המכיל מידע נוסף על השגיאה. השדהcomponentStackשלו מכיל עקבות מחסנית עם הרכיב שזרק, כמו גם את השמות ומיקומי המקור של כל רכיבי האב שלו. בייצור, שמות הרכיבים יוקטנו. אם תגדיר דיווח על שגיאות ייצור, תוכל לפענח את ערימת הרכיבים באמצעות מפות מקור באותו אופן כפי שהיית עושה עבור ערימות שגיאות JavaScript רגילות.
מחזירה
componentDidCatch לא אמור להחזיר כלום.
אזהרות
-
בעבר, היה מקובל לקרוא ל-
setStateבתוךcomponentDidCatchעל מנת לעדכן את ממשק המשתמש ולהציג את הודעת השגיאה החלפה. זה הוצא משימוש לטובת הגדרתstatic getDerivedStateFromError. -
ייצור ופיתוח של React שונים מעט באופן שבו
componentDidCatchמטפל בשגיאות. בפיתוח, השגיאות יבעבעו עדwindow, מה שאומר שכלwindow.onerrorאוwindow.addEventListener('error', callback)יירטו את השגיאות שנתפסו על ידיcomponentDidCatch. בייצור, במקום זאת, השגיאות לא יבעבעו, מה שאומר שכל מטפל בשגיאות קדמון יקבל רק שגיאות שלא נתפסו במפורש על ידיcomponentDidCatch.
componentDidMount()
אם תגדיר את שיטת componentDidMount, React יקרא לה כאשר הרכיב שלך יתווסף (רכוב) למסך. זהו מקום נפוץ להתחיל איסוף נתונים, הגדרת מנויים או מניפולציה של צמתים DOM.
אם אתה מיישם componentDidMount, אתה בדרך כלל צריך ליישם שיטות מחזור חיים אחרות כדי למנוע באגים. לדוגמה, אם componentDidMount קורא כמה state או props, אתה גם צריך ליישם את componentDidUpdate כדי לטפל בשינויים שלהם, ו-componentWillUnmount כדי לנקות את כל מה שcomponentDidMount עשה.
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}פרמטרים
componentDidMount אינו לוקח פרמטרים כלשהם.
מחזירה
componentDidMount לא אמור להחזיר כלום.
אזהרות
-
כאשר מצב קפדני פועל, בפיתוח React יתקשר ל-
componentDidMount, ואז יתקשר מיד ל-componentWillUnmount, ואז יתקשר שוב ל-componentDidMount. זה עוזר לך לשים לב אם שכחת ליישם אתcomponentWillUnmountאו שהלוגיקה שלו לא “משקפת” את מה שcomponentDidMountעושה. -
למרות שאתה יכול להתקשר ל-
setStateמיד ב-componentDidMount, עדיף להימנע מכך כשאפשר. זה יפעיל עיבוד נוסף, אבל זה יקרה לפני שהדפדפן יעדכן את המסך. זה מבטיח שלמרות שה-renderייקרא פעמיים במקרה זה, ה-user לא יראה את state הביניים. השתמש בדפוס זה בזהירות מכיוון שuse לעתים קרובות יש בעיות בביצועים. ברוב המקרים, אתה אמור להיות מסוגל להקצות את ה-state הראשוני ב-constructorבמקום זאת. עם זאת, זה יכול להיות נחוץ עבור מקרים כמו מודלים ועצות כלים כאשר אתה צריך למדוד צומת DOM לפני עיבוד משהו שתלוי בגודל או במיקומו.
componentDidUpdate(prevProps, prevState, snapshot?)
אם תגדיר את שיטת componentDidUpdate, React יקרא לה מיד לאחר שהרכיב שלך יעובד מחדש עם props או state מעודכן. שיטה זו אינה נקראת עבור העיבוד הראשוני.
אתה יכול use אותו כדי לתפעל את ה-DOM לאחר עדכון. זהו גם מקום נפוץ לבצע בקשות רשת כל עוד אתה משווה את ה-props הנוכחי ל-props הקודם (למשל, בקשת רשת לא תהיה נחוצה אם ה-props לא השתנה). בדרך כלל, use זה יחד עם componentDidMount ו-componentWillUnmount:
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}פרמטרים
-
prevProps: אביזרים לפני העדכון. השווה אתprevPropsל-this.propsכדי לקבוע מה השתנה. -
prevState: מצב לפני העדכון. השווה אתprevStateל-this.stateכדי לקבוע מה השתנה. -
snapshot: אם יישמת אתgetSnapshotBeforeUpdate,snapshotיכיל את הערך שהחזרת משיטה זו. אחרת, זה יהיהundefined.
מחזירה
componentDidUpdate לא אמור להחזיר כלום.
אזהרות
-
componentDidUpdateלא ייקרא אם הוגדרshouldComponentUpdateויחזיר אתfalse. -
ההיגיון בתוך
componentDidUpdateבדרך כלל צריך להיות עטוף בתנאים המשוויםthis.propsעםprevProps, וthis.stateעםprevState. אחרת, יש סיכון ליצירת לולאות אינסופיות. -
למרות שאתה יכול להתקשר ל-
setStateמיד ב-componentDidUpdate, עדיף להימנע מכך כשאפשר. זה יפעיל עיבוד נוסף, אבל זה יקרה לפני שהדפדפן יעדכן את המסך. זה מבטיח שלמרות שה-renderייקרא פעמיים במקרה זה, ה-user לא יראה את state הביניים. דפוס זה גורם לרוב לבעיות ביצועים של __TK_7, אך ייתכן שיהיה צורך במקרים נדירים כמו מודלים וטיפים של כלים כאשר אתה צריך למדוד צומת DOM לפני עיבוד משהו שתלוי בגודלו או במיקומו.
componentWillMount()
componentWillReceiveProps(nextProps)
componentWillUpdate(nextProps, nextState)
componentWillUnmount()
אם תגדיר את שיטת componentWillUnmount, React יקרא לה לפני שהרכיב שלך יוסר (לא מותקן) מהמסך. זהו מקום נפוץ לביטול אחזור נתונים או הסרת מינויים.
ההיגיון בתוך componentWillUnmount צריך “לשקף” את ההיגיון בתוך componentDidMount. לדוגמה, אם componentDidMount מגדיר מנוי, componentWillUnmount צריך לנקות את המנוי הזה. אם לוגיקת הניקוי ב-componentWillUnmount שלך קוראת כמה props או state, בדרך כלל תצטרך ליישם גם componentDidUpdate כדי לנקות משאבים (כגון מנויים) התואמים ל-props ול-state הישנים.
class ChatRoom extends Component {
state = {
serverUrl: 'https://localhost:1234'
};
componentDidMount() {
this.setupConnection();
}
componentDidUpdate(prevProps, prevState) {
if (
this.props.roomId !== prevProps.roomId ||
this.state.serverUrl !== prevState.serverUrl
) {
this.destroyConnection();
this.setupConnection();
}
}
componentWillUnmount() {
this.destroyConnection();
}
// ...
}פרמטרים
componentWillUnmount אינו לוקח פרמטרים כלשהם.
מחזירה
componentWillUnmount לא אמור להחזיר כלום.
אזהרות
- כאשר מצב קפדני פועל, בפיתוח React יתקשר ל-
componentDidMount, ואז יתקשר מיד ל-componentWillUnmount, ואז יתקשר שוב ל-componentDidMount. זה עוזר לך לשים לב אם שכחת ליישם אתcomponentWillUnmountאו שהלוגיקה שלו לא “משקפת” את מה שcomponentDidMountעושה.
forceUpdate(callback?)
מאלץ רכיב לעיבוד מחדש.
בדרך כלל, זה לא הכרחי. אם השיטה render של הרכיב שלך קוראת רק מ-this.props, this.state, או this.context, היא תוצג מחדש באופן אוטומטי כאשר תקרא ל-[setState](#props](#__)__K של אחד מההורים שלך. עם זאת, אם שיטת render של הרכיב שלך קוראת ישירות ממקור נתונים חיצוני, עליך להורות לReact לעדכן את ממשק user כאשר מקור נתונים זה משתנה. זה מה שforceUpdate מאפשר לך לעשות.
נסו להימנע מכל uses של forceUpdate וקראו רק מthis.props וthis.state בrender.
פרמטרים
- אופציונלי
callbackאם צוין, React יתקשר ל-callbackשסיפקת לאחר ביצוע העדכון.
מחזירה
forceUpdate לא מחזיר כלום.
אזהרות
- אם תתקשר ל-
forceUpdate, React יעבד מחדש מבלי לקרוא ל-shouldComponentUpdate.
getChildContext()
מאפשר לך לציין את הערכים עבור הקשר מדור קודם מסופק על ידי רכיב זה.
getSnapshotBeforeUpdate(prevProps, prevState)
אם תטמיע את getSnapshotBeforeUpdate, React יתקשר אליו מיד לפני ש-React יעדכן את ה-DOM. זה מאפשר לרכיב שלך ללכוד מידע מה-DOM (למשל מיקום הגלילה) לפני שהוא משתנה באופן פוטנציאלי. כל ערך שיוחזר על ידי שיטת מחזור חיים זו יועבר כפרמטר אל componentDidUpdate.
לדוגמה, אתה יכול use אותו בממשק משתמש כמו שרשור צ’אט שצריך לשמור על מיקום הגלילה שלו במהלך עדכונים:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// Are we adding new items to the list?
// Capture the scroll position so we can adjust scroll later.
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// If we have a snapshot value, we've just added new items.
// Adjust scroll so these new items don't push the old ones out of view.
// (snapshot here is the value returned from getSnapshotBeforeUpdate)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}בדוגמה לעיל, חשוב לקרוא את המאפיין scrollHeight ישירות ב-getSnapshotBeforeUpdate. זה לא בטוח לקרוא אותו ב-render, UNSAFE_componentWillReceiveProps, או UNSAFE_componentWillUpdate כי use קיים פער זמן פוטנציאלי בין התקשרות לשיטות אלו לבין עדכון KReact.
פרמטרים
-
prevProps: אביזרים לפני העדכון. השווה אתprevPropsל-this.propsכדי לקבוע מה השתנה. -
prevState: מצב לפני העדכון. השווה אתprevStateל-this.stateכדי לקבוע מה השתנה.
מחזירה
עליך להחזיר ערך תמונת מצב מכל סוג שתרצה, או null. הערך שהחזרת יועבר כארגומנט השלישי אל componentDidUpdate.
אזהרות
getSnapshotBeforeUpdateלא ייקרא אם הוגדרshouldComponentUpdateויחזיר אתfalse.
render()
שיטת render היא השיטה הנדרשת היחידה ברכיב מחלקה.
השיטה render צריכה לציין מה ברצונך שיופיע על המסך, לדוגמה:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}React עשוי להתקשר ל-render בכל רגע, אז אל תניח שהוא פועל בזמן מסוים. בדרך כלל, השיטה render צריכה להחזיר חתיכה של JSX, אבל כמה סוגי החזרות אחרים (כמו מחרוזות) נתמכים. כדי לחשב את ה-JSX המוחזר, שיטת render יכולה לקרוא this.props, this.state ו-this.context.
עליך לכתוב את שיטת render כפונקציה טהורה, כלומר היא צריכה להחזיר את אותה תוצאה אם props, state והקשר זהים. זה גם לא אמור להכיל תופעות לוואי (כמו הגדרת מנויים) או לקיים אינטראקציה עם APIs של הדפדפן. תופעות לוואי צריכות להתרחש במטפלי אירועים או בשיטות כמו componentDidMount.
פרמטרים
render אינו לוקח פרמטרים כלשהם.
מחזירה
render יכול להחזיר כל צומת React חוקי. זה כולל אלמנטים React כגון <div />, מחרוזות, מספרים, פורטלים, צמתים ריקים (null, undefined, true ו-false), ומערכים של React nodes.
אזהרות
-
יש לכתוב את
renderכפונקציה טהורה של props, state והקשר. לא אמורות להיות לזה תופעות לוואי. -
renderלא ייקרא אם הוגדרshouldComponentUpdateויחזיר אתfalse. -
כאשר מצב קפדני פועל, React יתקשר ל-
renderפעמיים בפיתוח ולאחר מכן יזרוק אחת מהתוצאות. זה עוזר לך להבחין בתופעות הלוואי המקריות שיש להזיז משיטתrender. -
אין התכתבות של אחד על אחד בין שיחת
renderלשיחתcomponentDidMountאוcomponentDidUpdateשלאחר מכן. חלק מתוצאות השיחהrenderעשויות להימחק על ידי React כאשר זה מועיל.
setState(nextState, callback?)
התקשר ל-setState כדי לעדכן את ה-state של רכיב ה-React שלך.
class Form extends Component {
state = {
name: 'Taylor',
};
handleNameChange = (e) => {
const newName = e.target.value;
this.setState({
name: newName
});
}
render() {
return (
<>
<input value={this.state.name} onChange={this.handleNameChange} />
<p>Hello, {this.state.name}.</p>
</>
);
}
}setState מציב שינויים בתורים ברכיב state. זה אומר לReact שהרכיב הזה והילדים שלו צריכים לעבד מחדש עם ה-state החדש. זו הדרך העיקרית שבה תעדכן את ממשק user בתגובה לאינטראקציות.
אתה יכול גם להעביר פונקציה ל-setState. זה מאפשר לך לעדכן את state על סמך ה-state הקודם:
handleIncreaseAge = () => {
this.setState(prevState => {
return {
age: prevState.age + 1
};
});
}אתה לא חייב לעשות זאת, אבל זה שימושי אם אתה רוצה לעדכן את state מספר פעמים במהלך אותו אירוע.
פרמטרים
-
nextState: או אובייקט או פונקציה.- אם תעביר אובייקט בתור
nextState, הוא יתמזג בצורה רדודה לתוךthis.state. - אם תעביר פונקציה בתור
nextState, היא תטופל כאל פונקציית עדכון. זה חייב להיות טהור, צריך לקחת את state וprops הממתינים כארגומנטים, ועליו להחזיר את האובייקט למיזוג רדוד לתוךthis.state. React ישים את פונקציית העדכון שלך בתור ותעבד מחדש את הרכיב שלך. במהלך העיבוד הבא, React יחשב את ה-state הבא על ידי החלת כל העדכונים בתור על ה-state הקודם.
- אם תעביר אובייקט בתור
-
אופציונלי
callback: אם צוין, React יתקשר ל-callbackשסיפקת לאחר ביצוע העדכון.
מחזירה
setState לא מחזיר כלום.
אזהרות
-
חשבו על
setStateכעל בקשה ולא על פקודה מיידית לעדכון הרכיב. כאשר רכיבים מרובים מעדכנים את state שלהם בתגובה לאירוע, React יבצע אצווה של העדכונים שלהם ויעבד אותם מחדש יחד במעבר אחד בסוף האירוע. במקרה הנדיר שאתה צריך לאלץ עדכון state מסוים להיות מיושם באופן סינכרוני, אתה יכול לעטוף אותו ב-flushSync, אבל זה עלול לפגוע בביצועים. -
setStatedoes not updatethis.stateimmediately. זה הופך את הקריאה שלthis.stateמיד לאחר הקריאה ל-setStateלמלכודת פוטנציאלית. במקום זאת, usecomponentDidUpdateאו הארגומנט setStatecallback, שכל אחד מהם מובטח יופעל לאחר החלת העדכון. אם אתה צריך להגדיר את state בהתבסס על ה-state הקודם, תוכל להעביר פונקציה ל-nextStateכמתואר לעיל.
shouldComponentUpdate(nextProps, nextState, nextContext)
אם תגדיר shouldComponentUpdate, React יקרא לזה כדי לקבוע אם ניתן לדלג על עיבוד מחדש.
אם אתה בטוח שאתה רוצה לכתוב את זה ביד, אתה יכול להשוות את this.props עם nextProps וthis.state עם nextState ולהחזיר את false כדי לומר לReact שניתן לדלג על העדכון.
class Rectangle extends Component {
state = {
isHovered: false
};
shouldComponentUpdate(nextProps, nextState) {
if (
nextProps.position.x === this.props.position.x &&
nextProps.position.y === this.props.position.y &&
nextProps.size.width === this.props.size.width &&
nextProps.size.height === this.props.size.height &&
nextState.isHovered === this.state.isHovered
) {
// Nothing has changed, so a re-render is unnecessary
return false;
}
return true;
}
// ...
}React קורא ל-shouldComponentUpdate לפני העיבוד כאשר props או state חדשים מתקבלים. ברירת המחדל היא true. שיטה זו אינה נקראת עבור העיבוד הראשוני או כאשר forceUpdate הוא used.
פרמטרים
nextProps: ה-props הבא שאיתו הרכיב עומד לרנדר. השווה אתnextPropsל-this.propsכדי לקבוע מה השתנה.nextState: ה-state הבא שאיתו הרכיב עומד לרנדר. השווה אתnextStateל-this.stateכדי לקבוע מה השתנה.nextContext: ההקשר הבא שאיתו הרכיב עומד לרנדר. השווה אתnextContextל-this.contextכדי לקבוע מה השתנה. זמין רק אם אתה מצייןstatic contextType(מודרני) אוstatic contextTypes(מדור קודם).
מחזירה
החזר true אם אתה רוצה שהרכיב יעבד מחדש. זו התנהגות ברירת המחדל.
החזר false כדי לומר לReact שניתן לדלג על עיבוד מחדש.
אזהרות
-
שיטה זו קיימת רק כאופטימיזציה של ביצועים. אם הרכיב שלך נשבר בלעדיו, תקן את זה קודם.
-
שקול להשתמש ב-
PureComponentבמקום לכתובshouldComponentUpdateביד.PureComponentמשווה באופן רדוד בין props ל-state, ומקטינה את הסיכוי שתדלג על עדכון הכרחי. -
איננו ממליצים לבצע בדיקות שוויון עמוקות או להשתמש ב-
JSON.stringifyב-shouldComponentUpdate. זה הופך את הביצועים לבלתי צפויים ותלויים במבנה הנתונים של כל אביזר ו-state. במקרה הטוב, אתה מסתכן בהחדרת דוכנים של מספר שניות לאפליקציה שלך, ובמקרה הגרוע אתה מסתכן בקריסתה. -
החזרת
falseאינה מונעת רכיבי צאצא לבצע רינדור מחדש כאשר state שלהם משתנה. -
החזרת
falseאינה מבטיחה שהרכיב לא יעבד מחדש. React יעשה use את ערך ההחזרה כרמז, אבל הוא עדיין עשוי לבחור לעבד מחדש את הרכיב שלך אם יש טעם לעשות זאת מסיבות אחרות.
UNSAFE_componentWillMount()
אם תגדיר UNSAFE_componentWillMount, React יקרא לו מיד אחרי ה-constructor. זה קיים רק מסיבות היסטוריות ולא צריך להיות used בשום קוד חדש. במקום זאת, use אחת מהחלופות:
- כדי לאתחל את state, הכריז על
stateכשדות מחלקה או הגדרthis.stateבתוךconstructor. - אם אתה צריך להפעיל תופעת לוואי או להגדיר מנוי, העבר את ההיגיון הזה ל-
componentDidMountבמקום זאת.
ראה דוגמאות להגירה הרחק ממחזורי חיים לא בטוחים.
פרמטרים
UNSAFE_componentWillMount אינו לוקח פרמטרים כלשהם.
מחזירה
UNSAFE_componentWillMount לא אמור להחזיר כלום.
אזהרות
-
UNSAFE_componentWillMountלא ייקרא אם הרכיב מיישםstatic getDerivedStateFromPropsאוgetSnapshotBeforeUpdate. -
למרות השם שלו,
UNSAFE_componentWillMountלא מבטיח שהרכיב יותקן אם האפליקציה שלך תכלול את התכונות המודרניות React של האפליקציה שלך כמוSuspense. אם ניסיון עיבוד מושעה (לדוגמה, בגלל שהקוד לא טען עדיין use עבור חלק מהילד) React יזרוק את העץ שנמצא בתהליך וינסה לבנות את הרכיב מאפס במהלך הניסיון הבא. זו הסיבה שהשיטה הזו “לא בטוחה”. קוד שמסתמך על הרכבה (כמו הוספת מנוי) צריך להיכנס אלcomponentDidMount. -
UNSAFE_componentWillMountהיא שיטת מחזור החיים היחידה שפועלת במהלך עיבוד שרת. לכל המטרות המעשיות, היא זהה ל-constructor, אז כדאי use אתconstructorעבור סוג זה של לוגיקה במקום זאת.
UNSAFE_componentWillReceiveProps(nextProps, nextContext)
אם תגדיר UNSAFE_componentWillReceiveProps, React יקרא לו כאשר הרכיב יקבל props חדש. זה קיים רק מסיבות היסטוריות ולא אמור להיות used בשום קוד חדש. במקום זאת, use אחת מהחלופות:
- אם אתה צריך להפעיל תופעת לוואי (לדוגמה, להביא נתונים, להפעיל אנימציה או לאתחל מחדש מנוי) בתגובה לשינויים באביזרי, העבר את ההיגיון הזה ל-
componentDidUpdateבמקום זאת. - אם אתה צריך להימנע מחישוב מחדש של חלק מהנתונים רק כאשר אבזר משתנה, use memoמסייע לאיזון במקום זאת.
- אם אתה צריך “לאפס” כמה state כאשר אבזר משתנה, שקול ליצור רכיב בשליטה מלאה או לא מבוקר לחלוטין עם מפתח במקום זאת.
- אם אתה צריך “להתאים” כמה state כאשר אבזר משתנה, בדוק אם אתה יכול לחשב את כל המידע הדרוש מ-props לבד במהלך העיבוד. אם אינך יכול, use
static getDerivedStateFromPropsבמקום זאת.
ראה דוגמאות להגירה הרחק ממחזורי חיים לא בטוחים.
פרמטרים
nextProps: ה-props הבא שהרכיב עומד לקבל מהרכיב האב שלו. השווה אתnextPropsל-this.propsכדי לקבוע מה השתנה.nextContext: ההקשר הבא שהרכיב עומד לקבל מהספק הקרוב ביותר. השווה אתnextContextל-this.contextכדי לקבוע מה השתנה. זמין רק אם אתה מצייןstatic contextType(מודרני) אוstatic contextTypes(מדור קודם).
מחזירה
UNSAFE_componentWillReceiveProps לא אמור להחזיר כלום.
אזהרות
-
UNSAFE_componentWillReceivePropsלא ייקרא אם הרכיב מיישםstatic getDerivedStateFromPropsאוgetSnapshotBeforeUpdate. -
למרות השם שלו,
UNSAFE_componentWillReceivePropsאינו מבטיח שהרכיב יקבל את ה-props האלה אם האפליקציה שלך use של התכונות המודרניות של React כמוSuspense. אם ניסיון רינדור הושעה (לדוגמה, רכיב __9 של האפליקציה עדיין לא הושעה, למשל, רכיב K __T לא הושעה), React יזרוק את העץ שנמצא בתהליך וינסה לבנות את הרכיב מאפס במהלך הניסיון הבא. עד לניסיון העיבוד הבא, ה-props עשוי להיות שונה. זו הסיבה שהשיטה הזו “לא בטוחה”. קוד שאמור לפעול רק עבור עדכונים מחויבים (כמו איפוס מנוי) צריך להיכנס אלcomponentDidUpdate. -
UNSAFE_componentWillReceivePropsלא אומר שהרכיב קיבל props שונה מהפעם הקודמת. אתה צריך להשוות אתnextPropsוthis.propsבעצמך כדי לבדוק אם משהו השתנה. -
React לא קורא
UNSAFE_componentWillReceivePropsעם props ראשוני במהלך ההרכבה. זה קורא לשיטה זו רק אם חלק מה-props של הרכיב עומדים להתעדכן. לדוגמה, קריאה ל-setStateלא מפעילה בדרך כלל אתUNSAFE_componentWillReceivePropsבתוך אותו רכיב.
UNSAFE_componentWillUpdate(nextProps, nextState)
אם תגדיר UNSAFE_componentWillUpdate, React יקרא לזה לפני עיבוד עם props או state החדשים. זה קיים רק מסיבות היסטוריות ולא אמור להיות used בשום קוד חדש. במקום זאת, use אחת מהחלופות:
- אם אתה צריך להפעיל תופעת לוואי (לדוגמה, להביא נתונים, להפעיל אנימציה או לאתחל מחדש מנוי) בתגובה לשינויים ב-prop או state, העבר את ההיגיון הזה ל-
componentDidUpdateבמקום זאת. - אם אתה צריך לקרוא מידע מה-DOM (לדוגמה, כדי לשמור את מיקום הגלילה הנוכחי) כדי שתוכל use אותו ב-
componentDidUpdateמאוחר יותר, קרא אותו בתוךgetSnapshotBeforeUpdateבמקום זאת.
ראה דוגמאות להגירה הרחק ממחזורי חיים לא בטוחים.
פרמטרים
nextProps: ה-props הבא שהרכיב עומד לעבד איתו. השווה אתnextPropsל-this.propsכדי לקבוע מה השתנה.nextState: ה-state הבא שהרכיב עומד לעבד איתו. השווה אתnextStateל-this.stateכדי לקבוע מה השתנה.
מחזירה
UNSAFE_componentWillUpdate לא אמור להחזיר כלום.
אזהרות
-
UNSAFE_componentWillUpdateלא ייקרא אם הוגדרshouldComponentUpdateויחזיר אתfalse. -
UNSAFE_componentWillUpdateלא ייקרא אם הרכיב מיישםstatic getDerivedStateFromPropsאוgetSnapshotBeforeUpdate. -
אין תמיכה להתקשר ל-
setState(או כל שיטה שמובילה לקריאה שלsetState, כמו שליחת פעולת Redux) במהלךcomponentWillUpdate. -
למרות השם שלו,
UNSAFE_componentWillUpdateאינו מבטיח שהרכיב יתעדכן אם האפליקציה שלך use תכונות מודרניות של React כמוSuspense. אם ניסיון רינדור מושעה (לדוגמה, בגלל use של האפליקציה שלך use הרכיב הילד __5 עדיין לא יטען __T רכיב 5) הרחק את העץ בתהליך ונסה לבנות את הרכיב מאפס במהלך הניסיון הבא. עד לניסיון העיבוד הבא, props וstate עשויים להיות שונים. זו הסיבה שהשיטה הזו “לא בטוחה”. קוד שאמור לפעול רק עבור עדכונים מחויבים (כמו איפוס מנוי) צריך להיכנס אלcomponentDidUpdate. -
UNSAFE_componentWillUpdateלא אומר שהרכיב קיבל props או state שונה מהפעם הקודמת. אתה צריך להשוות אתnextPropsעםthis.propsוnextStateעםthis.stateבעצמך כדי לבדוק אם משהו השתנה. -
React לא קורא
UNSAFE_componentWillUpdateעם props וstate ראשוני במהלך ההרכבה.
static childContextTypes
מאפשר לך לציין איזה הקשר מדור קודם מסופק על ידי רכיב זה.
static contextTypes
מאפשר לך לציין איזה הקשר מדור קודם נצרך על ידי רכיב זה.
static contextType
אם אתה רוצה לקרוא את this.context מרכיב הכיתה שלך, עליך לציין איזה הקשר הוא צריך לקרוא. ההקשר שאתה מציין בתור static contextType חייב להיות ערך שנוצר בעבר על ידי createContext.
class Button extends Component {
static contextType = ThemeContext;
render() {
const theme = this.context;
const className = 'button-' + theme;
return (
<button className={className}>
{this.props.children}
</button>
);
}
}static defaultProps
אתה יכול להגדיר static defaultProps כדי להגדיר את ברירת המחדל props עבור המחלקה. הם יהיו used עבור undefined וחסרים props, אך לא עבור null props.
לדוגמה, כך אתה מגדיר שהאבזר color צריך כברירת מחדל ל-'blue':
class Button extends Component {
static defaultProps = {
color: 'blue'
};
render() {
return <button className={this.props.color}>click me</button>;
}
}אם הפריט color אינו מסופק או שהוא undefined, הוא יוגדר כברירת מחדל ל-'blue':
<>
{/* this.props.color is "blue" */}
<Button />
{/* this.props.color is "blue" */}
<Button color={undefined} />
{/* this.props.color is null */}
<Button color={null} />
{/* this.props.color is "red" */}
<Button color="red" />
</>static propTypes
אתה יכול להגדיר static propTypes יחד עם ספריית prop-types כדי להצהיר על סוגי ה-props המקובלים על הרכיב שלך. סוגים אלו ייבדקו במהלך העיבוד ובפיתוח בלבד.
import PropTypes from 'prop-types';
class Greeting extends React.Component {
static propTypes = {
name: PropTypes.string
};
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}static getDerivedStateFromError(error)
אם תגדיר static getDerivedStateFromError, React יקרא לזה כאשר רכיב צאצא (כולל ילדים רחוקים) זורק שגיאה במהלך העיבוד. זה מאפשר לך להציג הודעת שגיאה במקום לנקות את ממשק המשתמש.
בדרך כלל, זה used יחד עם componentDidCatch המאפשרים לשלוח את דוח השגיאה לשירות ניתוח כלשהו. רכיב עם שיטות אלה נקרא גבול שגיאה.
פרמטרים
error: השגיאה שנזרקה. בפועל, זה בדרך כלל יהיה מופע שלErrorאבל זה לא מובטח כיuse JavaScript מאפשרthrowכל ערך, כולל מחרוזות או אפילוnull.
מחזירה
static getDerivedStateFromError צריך להחזיר את ה-state ואומר לרכיב להציג את הודעת השגיאה.
אזהרות
static getDerivedStateFromErrorצריכה להיות פונקציה טהורה. אם אתה רוצה לבצע תופעת לוואי (לדוגמה, להתקשר לשירות ניתוח), עליך ליישם גםcomponentDidCatch.
static getDerivedStateFromProps(props, state)
אם תגדיר static getDerivedStateFromProps, React יקרא לזה ממש לפני הקריאה ל-render, הן בהרכבה הראשונית והן בעדכונים הבאים. זה אמור להחזיר אובייקט כדי לעדכן את ה-state, או null כדי לעדכן כלום.
שיטה זו קיימת עבור מקרים נדירים של use כאשר ה-state תלוי בשינויים ב-props לאורך זמן. לדוגמה, רכיב Form זה מאפס את ה-email state כאשר מאפיין userID משתנה:
class Form extends Component {
state = {
email: this.props.defaultEmail,
prevUserID: this.props.userID
};
static getDerivedStateFromProps(props, state) {
// Any time the current user changes,
// Reset any parts of state that are tied to that user.
// In this simple example, that's just the email.
if (props.userID !== state.prevUserID) {
return {
prevUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}
// ...
}שים לב שתבנית זו מחייבת אותך לשמור ערך קודם של הפרופס (כמו userID) ב-state (כמו prevUserID).
פרמטרים
props: ה-props הבא שאיתו הרכיב עומד לרנדר.state: ה-state הבא שהרכיב עומד לעשות איתו.
מחזירה
static getDerivedStateFromProps להחזיר אובייקט כדי לעדכן את ה-state, או null כדי לעדכן כלום.
אזהרות
-
שיטה זו מופעלת על כל רינדור, ללא קשר ל-cause. זה שונה מ-
UNSAFE_componentWillReceiveProps, המופעל רק כאשר האב מבצע עיבוד מחדש ולא כתוצאה מ-setStateמקומי. -
לשיטה זו אין גישה למופע הרכיב. אם תרצה, תוכל מחדשuse קוד כלשהו בין
static getDerivedStateFromPropsלשיטות המחלקה האחרות על ידי חילוץ פונקציות טהורות של הרכיב props וstate מחוץ להגדרת המחלקה.
שימוש
הגדרת רכיב מחלקה
כדי להגדיר רכיב React כמחלקה, הרחב את המחלקה המובנית Component והגדר שיטה render:
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}React יקרא לשיטת render שלך בכל פעם שהוא צריך להבין מה להציג על המסך. בדרך כלל, תחזיר כמה JSX ממנו. שיטת render שלך צריכה להיות פונקציה טהורה: היא צריכה לחשב רק את ה-JSX.
בדומה לרכיבי פונקציה, רכיב מחלקה יכול לקבל מידע על ידי props מהרכיב האב שלו. עם זאת, התחביר לקריאת props שונה. לדוגמה, אם רכיב האב מעבד את <Greeting name="Taylor" />, אז אתה יכול לקרוא את האביזר name מ-this.props, כמו this.props.name:
import { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
שים לב ש-Hooks (פונקציות שמתחילות ב-use, כמו useState) אינן נתמכות בתוך רכיבי מחלקה.
הוספת state לרכיב מחלקה
כדי להוסיף state למחלקה, הקצה אובייקט למאפיין בשם state. כדי לעדכן את state, התקשר אל this.setState.
import { Component } from 'react'; export default class Counter extends Component { state = { name: 'Taylor', age: 42, }; handleNameChange = (e) => { this.setState({ name: e.target.value }); } handleAgeChange = () => { this.setState({ age: this.state.age + 1 }); }; render() { return ( <> <input value={this.state.name} onChange={this.handleNameChange} /> <button onClick={this.handleAgeChange}> Increment age </button> <p>Hello, {this.state.name}. You are {this.state.age}.</p> </> ); } }
הוספת שיטות מחזור חיים לרכיב מחלקה
יש כמה שיטות מיוחדות שאתה יכול להגדיר בכיתה שלך.
אם תגדיר את שיטת componentDidMount, React יקרא לה כאשר הרכיב שלך יתווסף (רכוב) למסך. React יקרא ל-componentDidUpdate לאחר שהרכיב שלך יעבד מחדש עקב שינוי ב-props או state. React יקרא ל-componentWillUnmount לאחר שהרכיב שלך הוסר (לא מותקן) מהמסך.
אם אתה מיישם componentDidMount, אתה בדרך כלל צריך ליישם את כל שלושת מחזורי החיים כדי למנוע באגים. לדוגמה, אם componentDidMount קורא כמה state או props, אתה גם צריך ליישם את componentDidUpdate כדי לטפל בשינויים שלהם, ואת componentWillUnmount כדי לנקות את כל מה שcomponentDidMount עשה.
לדוגמה, רכיב ChatRoom זה שומר על חיבור צ’אט מסונכרן עם props וstate:
import { Component } from 'react'; import { createConnection } from './chat.js'; export default class ChatRoom extends Component { state = { serverUrl: 'https://localhost:1234' }; componentDidMount() { this.setupConnection(); } componentDidUpdate(prevProps, prevState) { if ( this.props.roomId !== prevProps.roomId || this.state.serverUrl !== prevState.serverUrl ) { this.destroyConnection(); this.setupConnection(); } } componentWillUnmount() { this.destroyConnection(); } setupConnection() { this.connection = createConnection( this.state.serverUrl, this.props.roomId ); this.connection.connect(); } destroyConnection() { this.connection.disconnect(); this.connection = null; } render() { return ( <> <label> Server URL:{' '} <input value={this.state.serverUrl} onChange={e => { this.setState({ serverUrl: e.target.value }); }} /> </label> <h1>Welcome to the {this.props.roomId} room!</h1> </> ); } }
שים לב שבפיתוח כאשר מצב קפדני פועל, React יתקשר ל-componentDidMount, יתקשר מיד ל-componentWillUnmount, ואז יתקשר שוב ל-componentDidMount. זה עוזר לך לשים לב אם שכחת ליישם את componentWillUnmount או שהלוגיקה שלו לא “משקפת” את מה שcomponentDidMount עושה.
תופסת שגיאות רינדור עם גבול שגיאה
כברירת מחדל, אם האפליקציה שלך זורקת שגיאה במהלך העיבוד, React יסיר את ממשק המשתמש שלו מהמסך. כדי למנוע זאת, אתה יכול לעטוף חלק ממשק המשתמש שלך לתוך גבול שגיאה. גבול שגיאה הוא רכיב מיוחד המאפשר לך להציג ממשק משתמש חלופי במקום החלק שקרס - לדוגמה, הודעת שגיאה.
כדי ליישם רכיב גבול שגיאה, עליך לספק static getDerivedStateFromError המאפשר לך לעדכן את state בתגובה לשגיאה ולהציג הודעת שגיאה ל-user. אתה יכול גם ליישם אופציונלי componentDidCatch כדי להוסיף קצת היגיון נוסף, למשל, כדי להתחבר לשגיאה לשירות ניתוח.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, info) {
// Example "componentStack":
// in ComponentThatThrows (created by App)
// in ErrorBoundary (created by App)
// in div (created by App)
// in App
logErrorToMyService(error, info.componentStack);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return this.props.fallback;
}
return this.props.children;
}
}לאחר מכן תוכל לעטוף בו חלק מעץ הרכיבים שלך:
<ErrorBoundary fallback={<p>Something went wrong</p>}>
<Profile />
</ErrorBoundary>אם Profile או הרכיב הצאצא שלו יגרמו שגיאה, ErrorBoundary “יתפוס” את השגיאה הזו, יציג ממשק משתמש חלופי עם הודעת השגיאה שסיפקת, וישלח דוח שגיאות ייצור לשירות דיווח השגיאות שלך.
אתה לא צריך לעטוף כל רכיב לתוך גבול שגיאה נפרד. כאשר אתה חושב על הפירוט של גבולות השגיאה, שקול היכן הגיוני להציג הודעת שגיאה. לדוגמה, באפליקציית הודעות, הגיוני למקם גבול שגיאה סביב רשימת השיחות. זה גם הגיוני למקם אחת סביב כל הודעה בודדת. עם זאת, לא יהיה הגיוני להציב גבול סביב כל אווטאר.
חלופות
העברת רכיב פשוט ממחלקה לפונקציה
בדרך כלל, אתה תגדיר רכיבים כפונקציות במקום זאת.
לדוגמה, נניח שאתה ממיר את רכיב המחלקה Greeting הזה לפונקציה:
import { Component } from 'react'; class Greeting extends Component { render() { return <h1>Hello, {this.props.name}!</h1>; } } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
הגדר פונקציה בשם Greeting. זה המקום שבו תעביר את גוף הפונקציה render שלך.
function Greeting() {
// ... move the code from the render method here ...
}במקום this.props.name, הגדר את הפרופס name באמצעות תחביר ההרס וקרא אותו ישירות:
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}הנה דוגמה מלאה:
function Greeting({ name }) { return <h1>Hello, {name}!</h1>; } export default function App() { return ( <> <Greeting name="Sara" /> <Greeting name="Cahal" /> <Greeting name="Edite" /> </> ); }
import { Component } from 'react'; export default class Counter extends Component { state = { name: 'Taylor', age: 42, }; handleNameChange = (e) => { this.setState({ name: e.target.value }); } handleAgeChange = (e) => { this.setState({ age: this.state.age + 1 }); }; render() { return ( <> <input value={this.state.name} onChange={this.handleNameChange} /> <button onClick={this.handleAgeChange}> Increment age </button> <p>Hello, {this.state.name}. You are {this.state.age}.</p> </> ); } }
התחל בהכרזה על פונקציה עם המשתנים הנחוצים state:
import { useState } from 'react';
function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
// ...לאחר מכן, המר את מטפלי האירועים:
function Counter() {
const [name, setName] = useState('Taylor');
const [age, setAge] = useState(42);
function handleNameChange(e) {
setName(e.target.value);
}
function handleAgeChange() {
setAge(age + 1);
}
// ...לבסוף, החלף את כל ההפניות שמתחילות ב-this במשתנים ובפונקציות שהגדרת ברכיב שלך. לדוגמה, החלף את this.state.age ב-age, והחלף את this.handleNameChange ב-handleNameChange.
להלן רכיב שעבר המרה מלאה:
import { useState } from 'react'; export default function Counter() { const [name, setName] = useState('Taylor'); const [age, setAge] = useState(42); function handleNameChange(e) { setName(e.target.value); } function handleAgeChange() { setAge(age + 1); } return ( <> <input value={name} onChange={handleNameChange} /> <button onClick={handleAgeChange}> Increment age </button> <p>Hello, {name}. You are {age}.</p> </> ) }
העברת רכיב עם שיטות מחזור חיים ממחלקה לפונקציה
נניח שאתה ממיר את רכיב המחלקה ChatRoom עם שיטות מחזור חיים לפונקציה:
import { Component } from 'react'; import { createConnection } from './chat.js'; export default class ChatRoom extends Component { state = { serverUrl: 'https://localhost:1234' }; componentDidMount() { this.setupConnection(); } componentDidUpdate(prevProps, prevState) { if ( this.props.roomId !== prevProps.roomId || this.state.serverUrl !== prevState.serverUrl ) { this.destroyConnection(); this.setupConnection(); } } componentWillUnmount() { this.destroyConnection(); } setupConnection() { this.connection = createConnection( this.state.serverUrl, this.props.roomId ); this.connection.connect(); } destroyConnection() { this.connection.disconnect(); this.connection = null; } render() { return ( <> <label> Server URL:{' '} <input value={this.state.serverUrl} onChange={e => { this.setState({ serverUrl: e.target.value }); }} /> </label> <h1>Welcome to the {this.props.roomId} room!</h1> </> ); } }
ראשית, ודא שה-componentWillUnmount שלך עושה את ההיפך מ-componentDidMount. בדוגמה שלמעלה, זה נכון: הוא מנתק את החיבור שcomponentDidMount יוצר. אם היגיון כזה חסר, הוסף אותו תחילה.
לאחר מכן, ודא ששיטת ה-componentDidUpdate שלך מטפלת בשינויים בכל props וstate שבה אתה משתמש ב-componentDidMount. בדוגמה שלמעלה, componentDidMount קורא ל-setupConnection שקורא this.state.serverUrl ו-this.props.roomId. זו הסיבה שcomponentDidUpdate בודק אם this.state.serverUrl וthis.props.roomId השתנו, ומאפס את החיבור אם כן. אם ההיגיון componentDidUpdate שלך חסר או לא מטפל בשינויים בכל props וstate הרלוונטיים, תקן זאת תחילה.
בדוגמה שלמעלה, ההיגיון בתוך שיטות מחזור החיים מחבר את הרכיב למערכת מחוץ ל-React (שרת צ’אט). כדי לחבר רכיב למערכת חיצונית, תאר את ההיגיון הזה כאפקט יחיד:
import { useState, useEffect } from 'react';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
}הקריאה useEffect זו מקבילה להיגיון בשיטות מחזור החיים שלמעלה. אם שיטות מחזור החיים שלך עושות מספר דברים לא קשורים, חלק אותם למספר אפקטים עצמאיים. הנה דוגמה מלאה שתוכל לשחק איתה:
import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; export default function ChatRoom({ roomId }) { const [serverUrl, setServerUrl] = useState('https://localhost:1234'); useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; }, [roomId, serverUrl]); return ( <> <label> Server URL:{' '} <input value={serverUrl} onChange={e => setServerUrl(e.target.value)} /> </label> <h1>Welcome to the {roomId} room!</h1> </> ); }
העברת רכיב עם הקשר ממחלקה לפונקציה
בדוגמה זו, רכיבי הכיתה Panel וButton קוראים את הקשר מ-this.context:
import { createContext, Component } from 'react'; const ThemeContext = createContext(null); class Panel extends Component { static contextType = ThemeContext; render() { const theme = this.context; const className = 'panel-' + theme; return ( <section className={className}> <h1>{this.props.title}</h1> {this.props.children} </section> ); } } class Button extends Component { static contextType = ThemeContext; render() { const theme = this.context; const className = 'button-' + theme; return ( <button className={className}> {this.props.children} </button> ); } } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) }
כאשר אתה ממיר אותם לרכיבי פונקציה, החלף את this.context בקריאות useContext:
import { createContext, useContext } from 'react'; const ThemeContext = createContext(null); function Panel({ title, children }) { const theme = useContext(ThemeContext); const className = 'panel-' + theme; return ( <section className={className}> <h1>{title}</h1> {children} </section> ) } function Button({ children }) { const theme = useContext(ThemeContext); const className = 'button-' + theme; return ( <button className={className}> {children} </button> ); } function Form() { return ( <Panel title="Welcome"> <Button>Sign up</Button> <Button>Log in</Button> </Panel> ); } export default function MyApp() { return ( <ThemeContext.Provider value="dark"> <Form /> </ThemeContext.Provider> ) }