我想我就是无法理解这个问题,我已经尝试了大概六次并且总是求助于
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”不可分配给目标属性。
我总是喜欢这样做:
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 */}
/>
您可以更改组件的定义以允许 React html 按钮道具
class MyButton extends React.Component<MyButtonProps & React.HTMLProps<HTMLButtonElement>, {}> {
render() {
return <button {...this.props}/>;
}
}
这将告诉打字稿编译器您想要输入按钮道具以及“MyButtonProps”
似乎上面的答案已经过时了。
在我的例子中,我用功能组件包装了一个样式组件,但仍然想公开常规的 HTML 按钮属性。
export const Button: React.FC<ButtonProps &
React.HTMLProps<HTMLButtonElement>> = ({
children,
icon,
...props,
}) => (
<StyledButton {...props}>
{icon && <i className="material-icons">{icon}</i>}
{children}
</StyledButton>
);
这通过使用类型(而不是接口)对我有用:
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
children: React.ReactNode;
icon?: React.ReactNode;
};
function Button({ children, icon, ...props }: ButtonProps) {
return (
<button {...props}>
{icon && <i className="icon">{icon}</i>}
{children}
</button>
);
}
这就是我在扩展原生元素时所做的:
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 元素的引用。
这是我每次想要扩展 HTML 元素时使用的方法。
import { JSX } from 'react';
type ButtonProps = JSX.IntrinsicElements['button']
type DivProps = JSX.IntrinsicElements['div']
import * as React from "react";
interface Props extends React.HTMLProps<HTMLInputElement> {
label?: string;
}
export default function FormFileComponent({ label, ...props }: Props) {
return (
<div>
<label htmlFor={props?.id}></label>
<input type="file" {...props} />
</div>
);
}
import React, { DetailedHTMLProps, HTMLAttributes} from 'react';
DetailedHTMLProps<HTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
type DetailedHTMLProps<E extends HTMLAttributes<T>, T> = ClassAttributes<T> & E;
您可以创建自己的类型来缩短我们的案例(这似乎是常见情况)。
import React, { ClassAttributes, HTMLAttributes} from 'react';
type HTMLProps<T> = ClassAttributes<T> & HTMLAttributes<T>;
export interface ButtonProps extends HTMLProps<HTMLButtonElement> {
variant: 'contained' | 'outlined';
}
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 = forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
return (
<button key="key is accepted" ref={ref} {...props}>
{props.children}
</button>
);
},
);
如果您使用“@emotion/styled”中的样式化组件,则所有答案都不起作用。
我必须更深入一点。
import styled from "@emotion/styled";
import React, { ButtonHTMLAttributes } from 'react';
export type ButtonVariant = 'text' | 'filled' | 'outlined';
export const ButtonElement = styled.button`
display: flex;
align-items: center;
justify-content: center;
padding: 12px 16px;
`;
export interface ButtonProps {
variant: ButtonVariant;
}
export const Button: React.FC<ButtonProps & React.DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>> = ({
children,
variant,
...props
}) => (
<ButtonElement
{...props}
>
{children}
</ButtonElement>
);
这种样式允许您传递按钮具有的所有属性,更重要的是,将 {...props} 填充到 ButtonElement 可以让您轻松地使用样式组件重用 Button,以一种好的方式进行您想要的 css 更改
import { Button } from '@components/Button';
export const MySpecificButton = styled(Button)`
color: white;
background-color: green;
`;
您需要扩展您的接口。
import {ButtonHTMLAttributes, ReactNode} from "react";
export interface ButtonProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>{
appearance: 'primary' | 'ghost';
children: ReactNode;
}
我帮我解决了这个代码,你只需要从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>;
};
import { FC, HTMLProps } from 'react';
const Input: FC<HTMLProps<HTMLInputElement>> = (props) => {
return <input {...props} />;
};
private yourMethod(event: React.MouseEvent<HTMLButtonElement>): void {
event.currentTarget.disabled = true;
}
<Button
onClick={(event) => this.yourMethod(event)}
/>
我今天遇到了同样的问题,这是我解决的方法:
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。
我让这个工作了。不知何故,使用
HtmlHTMLAttributes
扩展道具对我来说不起作用。有效的是使用 ComponentPropsWithoutRef
,如下所示:
import clsx from "clsx"
import { FC } from "react";
interface InputProps
extends React.ComponentPropsWithoutRef<'input'>{
className?: string;
}
const Input: FC<InputProps> = ({ className, ...props}) => {
return (
<input
className={clsx('border-solid border-gray border-2 px-6 py-2 text-lg rounded-3xl w-full', className)}
{...props} />
)
}
export default Input
然后我可以使用通常的输入道具:
<Input
required
placeholder="First Name"
value={formState.firstName}
className="border-solid border-gray border-2 px-6 py-2 text-lg rounded-3xl w-full"
onChange={(e) =>
setFormState((s) => ({ ...s, firstName: e.target.value }))
}
/>
任何元素的简单方法
interface YOUR_INTERFACE_NAME extends YOUR_ELEMENT_TYPE{
props which you want to add or use in other elements
}
输入示例
interface MyInput extends InputHTMLAttributes<HTMLInputElement> {
name: string;
label: string;
...
}
按钮示例
interface MyButton extends ButtonHTMLAttributes<HTMLButtonElement> {
name: string;
label: string;
...
}
对所有其他元素使用相同的模式——从 React 导入这些类型或仅添加 REACT。在他们面前