Jak używać dzieci z bezstanowym komponentem funkcyjnym React w TypeScript?

85

Używając TypeScript z Reactem, nie musimy już rozszerzać React.Props, aby kompilator wiedział, że wszystkie właściwości komponentów reagujących mogą mieć dzieci:

interface MyProps { }

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

Jednak wydaje się, że nie ma to miejsca w przypadku bezstanowych komponentów funkcjonalnych:

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

Emituje błąd kompilacji:

Błąd: (102, 17) TS2339: Właściwość „dzieci” nie istnieje w typie „MyProps”.

Wydaje mi się, że dzieje się tak, ponieważ kompilator naprawdę nie może wiedzieć, że childrenw argumencie props zostanie podana funkcja waniliowa .

Zatem pytanie brzmi, jak powinniśmy używać dzieci w bezstanowych składnikach funkcjonalnych w TypeScript?

Mógłbym wrócić do starego sposobu MyProps extends React.Props, ale Propsinterfejs jest oznaczony jako przestarzały , a składniki bezstanowe nie mają ani nie obsługują, Props.refjak rozumiem.

Mogłem więc childrenręcznie zdefiniować rekwizyt:

interface MyProps {
  children?: React.ReactNode;
}

Po pierwsze: czy jest ReactNodeto właściwy typ?

Po drugie: muszę napisać dzieci jako opcjonalne ( ?), inaczej konsumenci pomyślą, że childrenma to być atrybut komponentu ( <MyStatelessComponent children={} />) i zgłoszą błąd, jeśli nie otrzymają wartości.

Wygląda na to, że czegoś mi brakuje. Czy ktoś może wyjaśnić, czy moim ostatnim przykładem jest sposób używania bezpaństwowych komponentów funkcjonalnych z dziećmi w Reakcie?

Aaron Beall
źródło

Odpowiedzi:

82

Aktualizacja React 16.8: Od React 16.8 nazwy React.SFCi React.StatelessComponentsą przestarzałe. Właściwie stały się aliasami React.FunctionComponenttypu lub React.FCw skrócie.

Używałbyś ich jednak w ten sam sposób:

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

Przed React 16.8 (starsze):

Na razie możesz użyć React.StatelessComponent<>typu jako:

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

Dodałem tam ustawienie zwracanego typu komponentu na React.StatelessComponenttyp.

W przypadku komponentu z własnymi niestandardowymi właściwościami (takimi jak MyPropsinterfejs):

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

Teraz propsma childrenwłaściwość jak i te z MyPropsinterfejsu.

Sprawdziłem to w maszynopisie w wersji 2.0.7

Dodatkowo możesz użyć React.SFCzamiast React.StatelessComponentdla zwięzłości.

Leone
źródło
Dzięki! Wygląda na to, że jestem na starej wersji typografii, która tego nie obsługuje ... Myślę, że nadszedł czas, aby ugryźć kulę i użyć TS 2.0 z@types
Aaronem Beallem
2
React.StatelessComponent/ React.SFCsą przestarzałe. React.FunctionComponentZamiast tego zaleca się odwołanie .
Alexander Kachkaev
Zauważ, że ta metoda nie działa, jeśli masz komponent ogólny
FunkeyFlo,
93

Możesz użyć React.PropsWithChildren<P>typu dla swoich rekwizytów:

interface MyProps { }

function MyComponent(props: React.PropsWithChildren<MyProps>) {
  return <div>{props.children}</div>;
}
baitun
źródło
0

Możesz użyć

interface YourProps { }
const yourComponent: React.SFC<YourProps> = props => {}
Jun Yin
źródło
0

Prostsza odpowiedź: użyj ReactNode:

interface MyProps {
  children?: React.ReactNode
}

Jeśli childrennie jest obowiązkowe, czy nie (czyli posiadające ?lub nie) zależy od komponentu. Jest ?to najbardziej zwięzły sposób wyrażenia tego, więc nie ma w tym nic złego.

O historii: To niekoniecznie była prawidłowa odpowiedź, gdy pierwotnie zapytano: Typ ReactNodezostał dodany (prawie) w swojej obecnej formie w marcu 2017 r. Tylko przez to żądanie ściągnięcia , ale prawie wszyscy czytający to dzisiaj powinni korzystać z wystarczająco nowoczesnej wersji React .

Na koniec, o przekazywaniu childrenjako „atrybut” (co w języku React oznaczałoby przekazywanie go jako „prop”, a nie atrybut): Jest to możliwe, ale w większości przypadków czyta się lepiej, gdy przekazuje się dzieciom JSX:

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

czyta łatwiej niż

<MyComponent children={<p>This is part of the children.</p>} />
chris6953
źródło