简体   繁体   English

在 React 中,使用 TypeScript,如何使用 RefForwardingComponent 和 forwardRef 将 ref 传递给自定义组件?

[英]In React, using TypeScript, how do I pass a ref to a custom component using RefForwardingComponent and forwardRef?

I'm trying to pass a ref to a custom component (so that I can set focus to the component).我正在尝试将 ref 传递给自定义组件(以便我可以将焦点设置到该组件)。

But I keep getting this error但我不断收到此错误

const RefComp: React.RefForwardingComponent<HTMLInputElement, Props>
Type '{ value: string; onChange: Dispatch<SetStateAction<string>>; ref: MutableRefObject<HTMLInputElement | undefined>; }'
is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
  Property 'ref' does not exist on type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.ts(2322)

This is my code这是我的代码

import * as React from 'react';
import {useRef, useState, RefForwardingComponent, forwardRef} from 'react';

interface Props {
    value: string;
    onChange(event: string): void;
}

const RefComp: RefForwardingComponent<HTMLInputElement, Props> = forwardRef<
    HTMLInputElement,
    Props
>(({value, onChange}, ref) => (
    <input
        value={value}
        onChange={event => onChange(event.target.value)}
        ref={ref}
    />
));

export default function App() {
    const [val, setVal] = useState('');
    const inputRef = useRef<HTMLInputElement>();

    return (
        <div className="App">
            <RefComp value={val} onChange={setVal} ref={inputRef} />
            <p>{val}</p>
        </div>
    );
}

Here's a codesandbox https://codesandbox.io/s/crimson-cdn-klfp5这是一个代码和框https://codesandbox.io/s/crimson-cdn-klfp5

The code seems to work fine, if I ignore the error.如果我忽略错误,代码似乎工作正常。 So not sure why I'm getting it...所以不知道为什么我得到它......

Can anyone please explain why I get the error, and how I fix it?任何人都可以解释为什么我收到错误,以及我如何解决它? :) :)

EDIT:编辑:

As mentioned in the comments you can work around this by adding ref to your props.如评论中所述,您可以通过向道具添加ref来解决此问题。

import * as React from 'react';
import {
    useRef,
    useState,
    RefForwardingComponent,
    forwardRef,
    MutableRefObject,
} from 'react';

interface Props {
    value: string;
    onChange(event: string): void;
    ref?: MutableRefObject<HTMLInputElement | null>;
}

const RefComp: RefForwardingComponent<HTMLInputElement, Props> = forwardRef<
    HTMLInputElement,
    Props
>(({value, onChange}, ref) => (
    <input
        value={value}
        onChange={event => onChange(event.target.value)}
        ref={ref}
    />
));

export default function App() {
    const [val, setVal] = useState('');
    const inputRef = useRef<HTMLInputElement>(null);

    return (
        <div className="App">
            <RefComp value={val} onChange={setVal} ref={inputRef} />
            <p>{val}</p>
        </div>
    );
}

But this feels wrong.但这感觉不对。 Now we're saying we have ref both as parts of the props, and as a second callback argument to the function passed to forwardRef现在我们说我们将ref作为 props 的一部分,以及作为传递给forwardRef的函数的第二个回调参数

My issue with this would probably be clearer if I wrote it like this如果我这样写,我的问题可能会更清楚

const RefComp: RefForwardingComponent<HTMLInputElement, Props> = forwardRef<
    HTMLInputElement,
    Props
>((props: Props, ref) => (
    <input
        value={props.value}
        onChange={event => props.onChange(event.target.value)}
        ref={ref /* here, props.ref is also available, but wouldn't work */ }
    />
));

EDIT 2:编辑2:

Here's a related question这是一个相关的问题

Typescript RefForwardingComponent not working 打字稿 RefForwardingComponent 不起作用

EDIT 3:编辑 3:

I found the relevant source code.我找到了相关的源代码。 https://github.com/DefinitelyTyped/DefinitelyTyped/blob/33f6179e0f25b0ca798ad89a667c0a27ea0c98dd/types/react/index.d.ts#L702 https://github.com/DefinitelyTyped/DefinitelyTyped/blob/33f6179e0f25b0ca798ad89a667c0a27ea0c98dd/types/react/index.d.ts#L702

function forwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;

So the forwardRef function returns a component of type ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>> .所以forwardRef函数返回一个ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>类型的组件。 This is a component that takes props of type PropsWithoutRef<P> intersected with RefAttributes<T> .这是一个组件,它采用与RefAttributes<T>相交的PropsWithoutRef<P>类型的道具。 Both types are also defined in the same file.这两种类型也在同一个文件中定义。

From what I understand the first one basically just excludes ref from P (which is Props in my original example).据我了解,第一个基本上只是从 P 中排除了ref (在我的原始示例中是Props )。 The second one is defined as第二个定义为

interface RefAttributes<T> extends Attributes {
    ref?: Ref<T>;
}

Given this information I really don't understand why I have to add ref to my own Props .鉴于这些信息,我真的不明白为什么我必须将ref添加到我自己的Props It really looks as if forwardRef should do it for me - even going as far as actually removing ref from my own Props ...看起来好像forwardRef应该为我做这件事 - 甚至实际上从我自己的Props删除ref ......

Can someone please explain what's going on here?有人可以解释一下这里发生了什么吗?

The problem was a bad type definition for RefComp .问题是RefComp的错误类型定义。 Removing that (letting TypeScript infer the type instead) and the code works just fine.删除它(让 TypeScript 推断类型)并且代码工作得很好。

import * as React from 'react';
import {useRef, useState, forwardRef} from 'react';

interface Props {
    value: string;
    onChange(event: string): void;
}

const RefComp = forwardRef<HTMLInputElement, Props>(
    ({value, onChange}, ref) => (
        <input
            value={value}
            onChange={event => onChange(event.target.value)}
            ref={ref}
        />
    ),
);

export default function App() {
    const [val, setVal] = useState('');
    const inputRef = useRef<HTMLInputElement>(null);

    React.useEffect(() => {
        if (inputRef.current) {
            inputRef.current.focus();
        }
    }, []);

    return (
        <div className="App">
            <RefComp value={val} onChange={setVal} ref={inputRef} />
            <p>{val}</p>
        </div>
    );
}

https://codesandbox.io/s/quizzical-liskov-bsruh https://codesandbox.io/s/quizzical-liskov-bsruh

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

相关问题 如何通过数组将 ref 传递给 typescript 中的 forwardRef 并做出反应? - How to pass ref via array to forwardRef in typescript and react? TypeScript,React 导致错误使用 forwardRef 和 props &amp; ref 是 null - TypeScript, React causing errors using forwardRef with props & ref is null 使用 React.forwardRef 与自定义 ref 道具的价值 - value of using React.forwardRef vs custom ref prop 反应 - 在组件中使用 forwardRef,typescript 错误 - 缺少属性“当前” - React - using forwardRef in component, typescript error - Property 'current' is missing 在 TypeScript 中使用带有子项的 forwardRef 组件 - Using a forwardRef component with children in TypeScript 在 React.forwardRef 中使用 ref.current - using ref.current in React.forwardRef 如何使用 react 和 typescript 将 ref 添加到 react 样式的组件 div? - How to add ref to a react styled component div using react and typescript? 使用 React.forwardRef 时在 React/TypeScript 中提供什么类型的 ref? - what type to give ref in React/TypeScript while using React.forwardRef? 使用 React.forwardRef 时将 prop 传递给组件 - Pass prop to Component when using React.forwardRef 如何在 react 和 typescript 中扩展 forwardRef 的引用类型以允许多个引用 - How to extend a ref type for forwardRef in react and typescript to allow multiple refs
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM