简体   繁体   English

在 TypeScript 中使用带有子项的 forwardRef 组件

[英]Using a forwardRef component with children in TypeScript

Using @types/react 16.8.2 and TypeScript 3.3.1.使用 @types/react 16.8.2 和 TypeScript 3.3.1。

I lifted this forward refs example straight from the React documentation and added a couple type parameters:我直接从React 文档中提取了这个前向引用示例,并添加了几个类型参数:

const FancyButton = React.forwardRef<HTMLButtonElement>((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

// You can now get a ref directly to the DOM button:
const ref = React.createRef<HTMLButtonElement>();
<FancyButton ref={ref}>Click me!</FancyButton>;

I get the following error in the last line under FancyButton :我在FancyButton下的最后一行收到以下错误:

Type ' { children: string; ref: RefObject<HTMLButtonElement>; }类型 ' { children: string; ref: RefObject<HTMLButtonElement>; } { children: string; ref: RefObject<HTMLButtonElement>; } { children: string; ref: RefObject<HTMLButtonElement>; } ' is not assignable to type ' IntrinsicAttributes & RefAttributes<HTMLButtonElement> '. { children: string; ref: RefObject<HTMLButtonElement>; } '不是分配给输入' IntrinsicAttributes & RefAttributes<HTMLButtonElement> ”。 Property ' children ' does not exist on type ' IntrinsicAttributes & RefAttributes<HTMLButtonElement> '.ts(2322)类型“ IntrinsicAttributes & RefAttributes<HTMLButtonElement> ”. IntrinsicAttributes & RefAttributes<HTMLButtonElement> (2322) 上不存在属性“ children

It would seem that the type definition for React.forwardRef's return value is wrong, not merging in the children prop properly. React.forwardRef 的返回值的类型定义似乎是错误的,没有正确合并 children 属性。 If I make <FancyButton> self-closing, the error goes away.如果我让<FancyButton>自动关闭,错误就会消失。 The lack of search results for this error leads me to believe I'm missing something obvious.缺少此错误的搜索结果使我相信我遗漏了一些明显的东西。

trevorsg, you need to pass the button properties: trevorsg,您需要传递按钮属性:

import * as React from 'react'

type ButtonProps = React.HTMLProps<HTMLButtonElement>

const FancyButton = React.forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => (
  <button type="button" ref={ref} className="FancyButton">
    {props.children}
  </button>
))

// You can now get a ref directly to the DOM button:
const ref = React.createRef<HTMLButtonElement>()

<FancyButton ref={ref}>Click me!</FancyButton>

ADDED:添加:

In recent versions of TS and @types/react, you can also use React.ComponentPropsWithoutRef<'button'> instead of React.HTMLProps<HTMLButtonElement>在 TS 和 @types/react 的最新版本中,您还可以使用React.ComponentPropsWithoutRef<'button'>代替React.HTMLProps<HTMLButtonElement>

The answer given by aMarCruz works well. aMarCruz 给出的答案效果很好。 However, if you also need to pass custom props to the FancyButton , here is how it can be done.但是,如果您还需要将自定义道具传递给FancyButton ,则可以通过以下方式完成。

interface FancyButtonProps extends React.ComponentPropsWithoutRef<'button'> {
    fooBar?: string; // my custom prop
}

const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>((props, ref) => (
    <button type="button" ref={ref} className="FancyButton">
        {props.children}
        {props.fooBar}
    </button>
));


/// Use later

// You can now get a ref directly to the DOM button:
const ref = React.createRef<HTMLButtonElement>()

<FancyButton ref={ref} fooBar="someValue">Click me!</FancyButton>

Just adding here for completion.只需在此处添加即可完成。

The answers given by aMarCruz and euvs both work, but they lie to consumers a little bit. aMarCruz 和 euvs 给出的答案都有效,但它们对消费者有点撒谎。 They say they accept all HTMLButtonElement props, but they ignore them instead of forwarding them to the button.他们说他们接受所有 HTMLButtonElement 道具,但他们忽略它们而不是将它们转发到按钮。 If you're just trying to merge in the children prop correctly, then you might want to use React.PropsWithChildren instead:如果你只是想正确地合并 children 道具,那么你可能想要使用 React.PropsWithChildren 代替:

import React from 'react';

interface FancyButtonProps {
    fooBar?: string; // my custom prop
}

const FancyButton = React.forwardRef<HTMLButtonElement, React.PropsWithChildren<FancyButtonProps>>((props, ref) => (
    <button type="button" ref={ref} className="fancy-button">
        {props.children}
        {props.fooBar}
    </button>
));

FancyButton.displayName = 'FancyButton';

Or explicitly add a children prop:或者明确添加一个 children 道具:

interface FancyButtonProps {
    children?: React.ReactNode;
    fooBar?: string; // my custom prop
}

const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>((props, ref) => (
    <button type="button" ref={ref} className="fancy-button">
        {props.children}
        {props.fooBar}
    </button>
));

FancyButton.displayName = 'FancyButton';

Or if you actually want to accept all the button props and forward them (let consumers choose button type="submit", for example), then you might want to use rest/spread:或者,如果您确实想要接受所有按钮道具并转发它们(例如,让消费者选择按钮类型 =“提交”),那么您可能需要使用 rest/spread:

import React from 'react';

interface FancyButtonProps extends React.ComponentPropsWithoutRef<'button'> {
    fooBar?: string; // my custom prop
}

const FancyButton = React.forwardRef<HTMLButtonElement, FancyButtonProps>(
    ({ children, className = '', fooBar, ...buttonProps }, ref) => (
        <button {...buttonProps} className={`fancy-button ${className}`} ref={ref}>
            {children}
            {fooBar}
        </button>
    ),
);

FancyButton.displayName = 'FancyButton';

A more compact solution:更紧凑的解决方案:

import React from 'react';

type ButtonProps = React.ComponentPropsWithRef<'button'>;

const FancyButton = React.forwardRef((props: ButtonProps) => (
    <button ref={ref}>
        {props.children}
    </button>
));

const ref = React.createRef<HTMLButtonElement>();
<FancyButton ref={ref}>Click Me!</FancyButton>;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM