在 React 和 TypeScript 中扩展 HTML 元素,同时保留 props

IT技术 reactjs typescript tsx
2021-05-23 00:48:58

我想我只是无法解决这个问题,我已经尝试了大约六次并且总是求助于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={...}/>

每当我尝试这种组合时,都会收到类似于以下内容的错误:

foo 的属性“ref”不可分配给目标属性。

4个回答

您可以更改组件的定义以允许响应 html 按钮props

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

这将告诉typescript编译器您要输入按钮props和“MyButtonProps”

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

在我的例子中,我用一个功能组件包装了一个样式组件,但仍然想公开常规的 HTML 按钮属性。

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

我总是喜欢这样做:

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

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

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 元素的引用