Definitelytyped: React-Komponenten sollten ReactNode zurückgeben, oder Kinder sollten ReactElement sein

Erstellt am 14. Juli 2017  ·  18Kommentare  ·  Quelle: DefinitelyTyped/DefinitelyTyped

  • [x] Ich habe versucht, das @types/react -Paket zu verwenden, und hatte Probleme.
  • [x] Ich habe versucht, die neueste stabile Version von tsc zu verwenden. https://www.npmjs.com/package/typescript
  • [x] Ich habe eine Frage, die für StackOverflow ungeeignet ist. (Bitte stellen Sie dort entsprechende Fragen).
  • [x] [Erwähne](https://github.com/blog/821-mention-somebody-they-re-notified) die Autoren (siehe Definitions by: in index.d.ts ), damit sie es können Antworten.

    • Autoren: @ericanderson @onigoetz @tkrotoff @digiguru @morcerf @johnnyreilly @bbenezech @pzavolinsky @DovydasNavickas

Die folgenden Komponenten

const SFC: React.StatelessComponent = (props) => props.children;

class C extends React.Component {
  render() {
    return this.props.children;
  }
}

die Fehler geben

Type '(props: { children?: ReactNode; }) => ReactNode' is not assignable to type 'StatelessComponent<{}>'.
  Type 'ReactNode' is not assignable to type 'ReactElement<any> | null'.
    Type 'undefined' is not assignable to type 'ReactElement<any> | null'.

Class 'C' incorrectly extends base class 'Component<{}, {}>'.
  Types of property 'render' are incompatible.
    Type '() => ReactNode' is not assignable to type '() => false | Element | null'.
      Type 'ReactNode' is not assignable to type 'false | Element | null'.
        Type 'undefined' is not assignable to type 'false | Element | null'.

Es funktioniert, wenn Sie children in Element .

Die Rückgabe children ist ziemlich üblich, wenn Provider-Komponenten erstellt werden, die nur etwas zu context hinzufügen.

Hilfreichster Kommentar

Ich verpacke derzeit children in React.Fragment , um dies zu umgehen.

Alle 18 Kommentare

Ich habe die folgenden Fixes für index.d.ts ausprobiert

-        render(): JSX.Element | null | false;
+        render(): ReactNode;

-        (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
+        (props: P & { children?: ReactNode }, context?: any): ReactNode;

Aber ich habe überall Fehler bekommen, als ich versuchte, Fussel zu machen, von denen ich nicht sicher bin, wie ich sie beheben soll.

TypeScript compile error: JSX element type 'ReactNode' is not a constructor function for JSX elements.

Nein, diese Änderung ist falsch. Du kannst derzeit nicht mehrere Elemente in React zurückgeben. Selbst wenn Sie es irgendwo tun, ist es höchstwahrscheinlich irgendwie in einem einzigen gekapselt.
Nur in React 16 mit Fiber könnte dies möglich sein :)

Ich bin mir nicht sicher, ob sie das Reaktionsverhalten geändert haben, aber der Redux / React-Autor hat die Möglichkeit gezeigt, this.props.children zurückzugeben, um dünne Wrapper zu erstellen (nur um childContext zu Elementen hinzuzufügen), wie in https://egghead.io/lessons/ zu sehen ist.

React-native ermöglicht es Ihnen jedoch, ein Array von JSX-Elementen von render zurückzugeben. Eine Problemumgehung besteht darin, this.props.children mit React.Children.only(this.props.children) zu umschließen, und es wird ausgelöst, wenn mehr als ein einzelnes Element als Root vorhanden ist

Richtig, Sie können React.Children.only verwenden, aber sowohl ReactNode als auch ReactElement sind gültige Werte von this.props.children .

const Title = props => <h1>{props.children}</h1>;
<Title>Woah</Title>

gültiger und angemessener React-Code ist.

Sie können ein Array von Elementen in React 16 zurückgeben, aber TS gibt einen Fehler aus, weil es denkt, dass Sie es nicht können.

Bearbeiten: tun Sie dies children: JSX.Element[]; , um es zu beheben

Aus meiner bisherigen Erfahrung scheint ReactNode gültig zu sein.

const Id: React.SFC<{}> = (props) => props.children

const App = ()= > <Id>This should work but instead fails</Id>

Besteht die Möglichkeit, dass sich dies in @types/react widerspiegelt?

Ohne dies kann ich keine React-Kinder eingeben

Ich verpacke derzeit children in React.Fragment , um dies zu umgehen.

Irgendwelche Updates dazu?

Ich bin mir nicht sicher, ob dies mehr oder weniger richtig ist, als children in React.Fragment , aber ich hatte Glück damit

return (children as React.ReactElement);

return <>{foo(}</>; ganze Nacht lang. <> ist eine Problemumgehung.

Das bereitet mir auch Probleme.

TL;DR:

Ich habe ein HOC, das einer bestimmten Komponente Requisiten hinzufügt, und ich versuche, es mit einer funktionalen Komponente zu verwenden, die return children; hat. Es funktioniert nur, wenn ich den Workaround return <>{children}</>; verwende.

Mehr Details:

Hier ist eine vereinfachte Version des HOC:

export interface ExtraProps {
  extraProp1: string;
}

export const withExtraProps = <P extends object>(Component: React.ComponentType<P>) => {
  return class extends React.Component<Omit<P, keyof ExtraProps>> {
    render() {
      const extraProps = {
        extraProp1: 'test'
      };

      return (
        <Component {...this.props as P} {...extraProps} />
      )
    }
  }
}

Hier ist eine vereinfachte Version der Funktionskomponente:

interface ComponentProps extends ExtraProps {
  children?: React.ReactNode;
  loadingComponent?: ReactElement;
}

export function ExampleComponent(props: ComponentProps) {
  const { children, loadingComponent } = props;

  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      await someAsyncCall();
      setLoading(false);
    }

    fetchData();
  });

  if (loading) {
    return loadingComponent || null;
  }

  return children;
}

// This line errors:
export const FeatureFlag = withExtraProps(ExampleComponent);

Ich bekomme folgenden Fehler:

Argument of type '(props: ComponentProps) => {} | null | undefined' is not assignable to parameter of type 'ComponentType<ComponentProps>'.
  Type '(props: ComponentProps) => {} | null | undefined' is not assignable to type 'FunctionComponent<ComponentProps>'.
    Type '{} | null | undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
      Type 'undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.

Wenn ich der ExampleComponent einen Rückgabetyp von ReactElement | null hinzufüge, hört es auf, sich über die Übergabe an die HOC zu beschweren, aber es gibt immer noch Fehler, wo ich die Kinder zurückgebe:

export function ExampleComponent(props: ComponentProps): ReactElement | null {
  ...
  ...
  return children; // Type 'ReactNode' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.

}

Wie bei den anderen hier funktioniert es, wenn ich es in return <>{children}</>; ändere, aber es fühlt sich grob und unnötig an.

Ich habe das _exakt_ gleiche Problem wie @kyrstenkelly - Eine HOC-Funktion, an die ein React.FC übergeben wird, das seine Kinder rendert.

Der <> children(...) </> Fix funktioniert, aber gibt es schon eine bessere Lösung?

Habe auch dieses Problem! Derzeit wird die vorgeschlagene Lösung der Verpackungslösung mit React.Fragment durchgeführt

Hier gilt das gleiche

interface IIntlMessageProps {
    id: string;
    valuesGiven?: {[key:string]:string};
}

// this doesn't work - -- TS2769 Type 'null' is not assignable to type '(nodes:ReactNodeARray) => ReactNode' | ... | undefined
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            {props.children}
        </FormattedMessage>
    )
};
//Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            <React.Fragment>{props.children}</React.Fragment>
        </FormattedMessage>
    )
};

// Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> | null = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            <>{props.children}</>
        </FormattedMessage>
    )
};

// Nope -- TS2769 Type '{}' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            {props.children ? props.children : undefined}
        </FormattedMessage>
    )
};


Ich glaube, ich habe alles versucht, was hier empfohlen wurde ... :( Irgendeine Ahnung?

Die Lösung ist, dass Sie es in Fragmente einpacken müssen.

import React from 'react'

const Something: React.FC = ({ children }) => (
 <> { children } </>
)

Dadurch wird der Fehler Type '({ children }: { children?: ReactNode; }) => ReactNode' is not assignable to type 'FunctionComponent behoben.

Wenn möglich, möchte ich Fragmente vermeiden und dafür sorgen, dass das JSX-Typsystem dieselben Arten von Konstrukten unterstützt, die JavaScript und Flow React unterstützen, wodurch TypeScript besser mit Bibliotheksmustern von Drittanbietern funktioniert.

Ein weiteres nicht ideales Ergebnis, das ich finde, ist, dass Fragmente den Komponentenbaum vertiefen, insbesondere in Utility-/Wrapper-Komponenten (Beispiel: React-Platzhalter). Casting in React.ReactElement scheint ein besserer Ansatz in dieser Art von Bibliotheken zu sein, aber ich möchte lieber nicht casten.

Ich habe versucht, diesen Typ zu ändern, bin aber bei der JSX-Typprüfung mit einer funktionalen Komponente des neuen Typs hängengeblieben. Ich habe den Zweig immer noch, hätte schwören können, dass ich eine PR gemacht habe, in der ich um Hilfe gebeten habe, kann ihn nicht wiederfinden ...

Okay, wenn der Typ Arrays von Knoten verbieten muss, bedeutet das nicht, dass er ReactText , ReactPortal , boolean , null und undefined verbieten sollte ReactElement tut.

Was ist der Grund dafür, diese zusätzlichen Typen zu verbieten?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen