HTML-elementen uitbreiden in React en TypeScript met behoud van rekwisieten

Ik kan hier mijn hoofd niet omheen draaien, denk ik, ik heb het waarschijnlijk zes keer geprobeerd en gebruik altijd any… Is er een legitieme manier om met een HTML te beginnen element, dat in een component wikkelen en dat in een ander component wikkelen zodat de HTML-rekwisieten overal doorheen gaan? In wezen het HTML-element aanpassen? Bijvoorbeeld iets als:

interface MyButtonProps extends React.HTMLProps<HTMLButtonElement> {}
class MyButton extends React.Component<MyButtonProps, {}> {
    render() {
        return <button/>;
    }
} 
interface MyAwesomeButtonProps extends MyButtonProps {}
class MyAwesomeButton extends React.Component<MyAwesomeButtonProps, {}> {
    render() {
        return <MyButton/>;
    }
}

Gebruik:

<MyAwesomeButton onClick={...}/>

Telkens wanneer ik dit soort compositie probeer, krijg ik een foutmelding die lijkt op:

Eigenschap ‘ref’ van foo kan niet worden toegewezen aan doeleigenschap.


Antwoord 1, autoriteit 100%

U kunt de definitie van uw component wijzigen om de rekwisieten van de react html-knop toe te staan

class MyButton extends React.Component<MyButtonProps & React.HTMLProps<HTMLButtonElement>, {}> {
    render() {
        return <button {...this.props}/>;
    }
}

Dat zal de typoscript-compiler vertellen dat je de knopprops samen met ‘MyButtonProps’ wilt invoeren


Antwoord 2, autoriteit 49%

Het lijkt erop dat het bovenstaande antwoord verouderd is.

In mijn geval verpak ik een gestileerde component met een functionele component, maar wil ik toch de reguliere HTML-knopeigenschappen weergeven.

export const Button: React.FC<ButtonProps &
  React.HTMLProps<HTMLButtonElement>> = ({
  ...props,
  children,
  icon
}) => (
  <StyledButton {...props}>
    {icon && <i className="material-icons">{icon}</i>}
    {children}
  </StyledButton>
);

Antwoord 3, autoriteit 47%

Ik doe het altijd graag op deze manier:

import React from 'react';
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  title: string;
  showIcon: boolean;
}
const Button: React.FC<ButtonProps> = ({ title, showIcon, ...props }) => {
  return (
    <button {...props}>
      {title}
      {showIcon && <Icon/>}
    </button>
  );
};

Dan kun je het volgende doen:

<Button
  title="Click me"
  onClick={() => {}} {/* You have access to the <button/> props */}
/>

Antwoord 4, autoriteit 4%

Dit is wat ik doe bij het uitbreiden van native elementen:

import React, { ButtonHTMLAttributes, forwardRef } from "react";
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
    myExtraProp1: string;
    myExtraProp2: string;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
    ({ myExtraProp1, myExtraProp2, ...props }, ref) => (
        <button
            {...props}
            ref={ref}
            // Do something with the extra props
        />
    ),
);
Button.displayName = "Button";

forwardRefzorgt ervoor dat u een verwijzing naar het onderliggende HTML-element kunt krijgen met refwanneer u de component gebruikt.


Antwoord 5, autoriteit 2%

Ik los deze code voor me op, je hoeft alleen maar ButtonHTMLAttributesvan react te importeren en dat is alles

import { ButtonHTMLAttributes } from "react";
interface MyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
    children: any;
}
export const MyButton = (props: ButtonI) => {
    const { children } = props;
    return <button {...props}>{children}</button>;
};

Antwoord 6

HTML-element uitbreiden met Ref & Sleutel

TL;DR

Als je `ref` en key moet kunnen accepteren, moet je typedefinitie dit lange lelijke ding gebruiken:

import React, { DetailedHTMLProps, HTMLAttributes} from 'react';
DetailedHTMLProps<HTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
Typedefinitie

Kijkend naar het typedefinitiebestand, is dit het type. Ik weet niet zeker waarom het niet korter is, het lijkt erop dat je hetzelfde HTMLElement altijd twee keer doorgeeft?

type DetailedHTMLProps<E extends HTMLAttributes<T>, T> = ClassAttributes<T> & E;
Verkorte gedetailleerde HTMLProps

Je zou je eigen type kunnen maken om dit voor ons geval in te korten (wat gebruikelijk lijkt te zijn).

import React, { ClassAttributes, HTMLAttributes} from 'react';
type HTMLProps<T> = ClassAttributes<T> & HTMLAttributes<T>;
export interface ButtonProps extends HTMLProps<HTMLButtonElement> {
  variant: 'contained' | 'outlined';
}
Voorbeeldcomponent
import React, {ClassAttributes, HTMLAttributes, ForwardedRef, forwardRef} from 'react';
type HTMLProps<T> = ClassAttributes<T> & HTMLAttributes<T>;
export interface ButtonProps extends HTMLProps<HTMLButtonElement> {
  variant: 'contained' | 'outlined';
}
export const Button: React.FC<ButtonProps> = forwardRef(
  (props : ButtonProps, ref: ForwardedRef<HTMLButtonElement>) => {
    return (
      <button key="key is accepted" ref={ref} {...props}>
        {props.children}
      </button>
    );
  },
);

Antwoord 7

U kunt dit doen om de knopeigenschappen uit te breiden

import { ButtonHTMLAttributes, ReactNode } from "react";
interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
    children: ReactNode;
}
const Button = ({ children, ...props }: Props): JSX.Element => {
    return <button {...props}>{children}</button>;
};

Other episodes