reactjs - Comment créer un composant React fonctionnel avec un type générique ?


J'essaie de créer un composant React qui prend un paramètre de type générique qui fera partie de son type de props.

Je veux une solution qui ressemblerait à quelque chose comme ceci :

interface TestProps<T> {
  value: T;
  onChange: (newValue: T) => void;
}

const Test: React.FC<TestProps<T>> = (props) => (
  <span>{props.value}</span>
);

J'ai vu qu'il y a un support pour cela dans TypeScript 2.9 et je suis sur la version 4.3.5.

L'utilisation de ceci ressemblerait à ceci :

const Usage: React.FC = () => (
  <div>
    <Test<Obj>
      value={{ name: 'test' }}
      onChange={(newValue) => {
        console.log(newValue.name);
      }}
    />
  </div>
);

Sandbox de code : https://codesandbox.io/s/react-typescript-playground-forked-8hu13?file=/src/index.tsx

Réponse #1

Vous devez réécrire votre composant Test de cette manière

const Test= <T,>(props:TestProps<T>) => (
    <span>Some component logic</span>
);

Pouvez-vous montrer la même chose avec React.FC<TestProps> ? Il est impossible de le faire avec FC.

Voici l'implémentation de FC :

interface FunctionComponent<P = {}> {
  (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
  // ... other static properties
}

Comme vous l'avez peut-être remarqué, FC est un type de fonction, pas un type de props.

MISE À JOUR

Vous pouvez créer une fonction d'ordre supérieur, mais je ne suis pas sûr que ça en vaille la peine

const WithGeneric = <T,>(): React.FC<TestProps<T>> =>
  (props: TestProps<T>) => (
    <span>Some component logic</span>
  );
const Test = WithGeneric<Obj>()

Réponse #2

La façon la plus simple est de faire de la FC générique une fonction régulière, et non une fonction fléchée. (React.PropsWithChildren<> imite ce que React.FC fait à votre type de props.)

function Test<T>(props: React.PropsWithChildren<TestProps<T>>) {
    return <span>Some component logic</span>;
}

Réponse #3

Dans mon cas, c'était comme les codes suivants :

export interface FormProps<T> {
  validator?: AnyObjectSchema;
  onSubmit?: (data: T) => void;
}

const Form = <T = any,>({
  children,
  validator,
}: PropsWithChildren<FormProps<T>>): JSX.Element => {
  ~~~

Et en utilisation :

type MyType = ...

<Form<MyType>
  validation={something}
  onSubmit={handleSomething}
>
  <SomeCompo />
  <AnotherSomeCompo />
</Form>