在保留道具的同时扩展React和TypeScript中的HTML元素

时间:2016-11-21 23:29:54

标签: reactjs typescript tsx

我只是无法绕过这个我想,我已经尝试了大约六次,总是诉诸any ...是否有合法的方式开始HTML元素,将其包装在组件中,并将其包装在另一个组件中,以便HTML props传递所有内容?基本上自定义HTML元素?例如,像:

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/>;
    }
}

用法:

<MyAwesomeButton onClick={...}/>

每当我尝试这种组合时,我都会收到类似于:

的错误
  

财产&#39; ref&#39; foo不能分配给目标财产。

8 个答案:

答案 0 :(得分:22)

您可以更改组件的定义以允许反应html按钮道具

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

这将告诉typescript编译器你想要输入按钮道具以及'MyButtonProps'

答案 1 :(得分:22)

似乎上面的答案已经过时了。

在我的案例中,我将样式化的组件与功能性组件包装在一起,但仍然希望公开常规的HTML按钮属性。

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

答案 2 :(得分:13)

我总是喜欢这样:

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>
  );
};

然后您可以做:

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

答案 3 :(得分:1)

  private yourMethod(event: React.MouseEvent<HTMLButtonElement>): void {
  event.currentTarget.disabled = true;
  }  

 <Button
 onClick={(event) => this.yourMethod(event)}
 />

答案 4 :(得分:1)

我今天遇到了同样的问题,这是我如何解决的问题:

ReactButtonProps.ts

import {
  ButtonHTMLAttributes,
  DetailedHTMLProps,
} from 'react';

/**
 * React HTML "Button" element properties.
 * Meant to be a helper when using custom buttons that should inherit native "<button>" properties.
 *
 * @example type MyButtonProps = {
 *   transparent?: boolean;
 * } & ReactButtonProps;
 */
export type ReactButtonProps = DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>;

Button-ish组件中的用法:

import classnames from 'classnames';
import React, { ReactNode } from 'react';
import { ReactButtonProps } from '../../types/react/ReactButtonProps';

type Props = {
  children: ReactNode;
  className?: string;
  mode?: BtnMode;
  transparent?: boolean;
} & ReactButtonProps;


const BtnCTA: React.FunctionComponent<Props> = (props: Props): JSX.Element => {
  const { children, className, mode = 'primary' as BtnMode, transparent, ...rest } = props;
  
  // Custom stuff with props

  return (
    <button
      {...rest} // This forward all given props (e.g: onClick)
      className={classnames('btn-cta', className)}
    >
      {children}
    </button>
  );
};

export default BtnCTA;

用法:

<BtnCTA className={'test'} onClick={() => console.log('click')}>
  <FontAwesomeIcon icon="arrow-right" />
  {modChatbot?.homeButtonLabel}
</BtnCTA>

我现在可以使用onClick,因为由于它是从ReactButtonProps扩展而被允许的,并且它通过...rest自动转发到DOM。

答案 5 :(得分:1)

我为我解决了这段代码,您只需要从react导入ButtonHTMLAttributes就可以了

import { ButtonHTMLAttributes } from "react";

interface MyButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
    children: any;
}

export const MyButton = (props: ButtonI) => {
    const { children } = props;
 
    return <button {...props}>{children}</button>;
};

答案 6 :(得分:1)

这就是我在扩展原生元素时所做的:

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";

forwardRef 确保您在使用组件时可以通过 ref 获得对底层 HTML 元素的引用。

答案 7 :(得分:0)

您可以这样做以扩展按钮属性

import { ButtonHTMLAttributes, ReactNode } from "react";

interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
    children: ReactNode;
}

const Button = ({ children, ...props }: Props): JSX.Element => {
    return <button {...props}>{children}</button>;
};