reactjs - איך להשתמש ב־children עם קומפוננט פונקציונלי סטטלי ב־React ב־TypeScript


באמצעות TypeScript עם React אין לנו צורך עוד להרחיב את React.Props כדי שהקומפיילר ידע שכל רכיבי ה-React יכולים להכיל ילדים:

interface MyProps { }

class MyComponent extends React.Component<MyProps, {}> {
  public render(): JSX.Element {
    return <div>{this.props.children}</div>;
  }
}

עם זאת, נראה שזה לא המצב עבור קומפוננטות פונקציונליות חסרות מצב:

const MyStatelessComponent = (props: MyProps) => {
  return (
    <div>{props.children}</div>
  );
};

מפיק את שגיאת הקומפילציה:

שגיאה:(102, 17) TS2339: התכונה 'children' אינה קיימת בסוג 'MyProps'.

אני מניח שזה בגלל שבאמת אין שום דרך למתרגם לדעת שפונקציה רגילה תקבל children בארגומנט props.

אז השאלה היא איך אנחנו צריכים להשתמש ב-children ברכיב פונקציונלי ללא מצב ב-TypeScript?

אני יכול לחזור לדרך הישנה של MyProps extends React.Props, אבל הממשק Props מסומן כמיושן, ורכיבים ללא מצב (stateless) אינם כוללים או תומכים ב-Props.ref כפי שאני מבין זאת.

כך שיכולתי להגדיר את הפרופ children באופן ידני:

interface MyProps {
  children?: React.ReactNode;
}

ראשית: האם ReactNode הוא הסוג הנכון?

שנית: אני צריך לכתוב את children כאופציונלי (?) אחרת הצרכנים יחשבו ש-children אמור להיות מאפיין של הקומפוננטה (<MyStatelessComponent children={} />), ויעלו שגיאה אם לא יסופק ערך.

נראה שאני מפספס משהו. מישהו יכול להבהיר אם הדוגמה האחרונה שלי היא הדרך להשתמש ברכיבים פונקציונליים ללא מצב עם ילדים ב-React?

תשובה #1

אתה יכול להשתמש בסוג React.PropsWithChildren<P> עבור ה-props שלך:

interface MyProps { }

function MyComponent(props: React.PropsWithChildren<MyProps>) {
  return <div>{props.children}</div>;
}

תשובה #2

עדכון React 16.8: מאז React 16.8, השמות React.SFC ו-React.StatelessComponent אינם בשימוש. למעשה, הם הפכו לכינויים עבור סוג React.FunctionComponent או בקיצור React.FC.

עם זאת, הייתם משתמשים בהם באותה הדרך:

const MyStatelessComponent : React.FunctionComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

לפני React 16.8 (ישן):

כרגע, אתה יכול להשתמש בסוג React.StatelessComponent<>, כך:

const MyStatelessComponent : React.StatelessComponent<{}> = props =>
    <div>{props.children}</div>

מה שהוספתי שם הוא הגדרת סוג ההחזרה של הקומפוננטה לסוג React.StatelessComponent.

לרכיב עם props מותאמים אישית משלך (כמו ממשק MyProps):

const MyStatelessComponent : React.StatelessComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

כעת, ל-props יש את הנכסים של הילדים וגם את אלה של ממשק MyProps.

בדקתי את זה בגרסת TypeScript 2.0.7

בנוסף, אתה יכול להשתמש ב-React.SFC במקום React.StatelessComponent כדי לקצר.

תשובה #3

תשובה פשוטה יותר: השתמש ב-ReactNode:

interface MyProps {
  children?: React.ReactNode
}

אם children הוא אופציונלי או לא (כלומר אם יש ? או לא) תלוי ברכיב שלך. ה-? הוא הדרך התמציתית ביותר לבטא זאת, כך שאין בכך שום דבר לא בסדר.

על היסטוריה: זו לא הייתה בהכרח התשובה הנכונה כאשר נשאלה במקור: סוג ReactNode נוסף (בכמעט) הצורה הנוכחית שלו במרץ 2017 על ידי בקשת משיכה זו בלבד, אך כמעט כל מי שקורא זאת היום צריך להיות בגרסה מודרנית מספיק של React.

לבסוף, לגבי העברת children כ"תכונה" (שבמונחי React, יהיה להעביר אותו כ"prop", לא כתכונה): זה אפשרי, אך ברוב המקרים זה נקרא טוב יותר כאשר מעבירים ילדים של JSX:

<MyComponent>
  <p>This is part of the children.</p>
</MyComponent>

קורא יותר בקלות מ

<MyComponent children={<p>This is part of the children.</p>} />