Я пытаюсь передать ссылку на пользовательский компонент (чтобы я мог установить фокус на компонент).
Но я продолжаю получать эту ошибку
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)
Это мой код
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>
);
}
Вот коды и поле https://codesandbox.io/s/crimson-cdn-klfp5
Код, кажется, работает нормально, если я игнорирую ошибку. Поэтому не уверен, почему я получаю это ...
Может кто-нибудь объяснить, почему я получаю ошибку и как ее исправить? :)
РЕДАКТИРОВАТЬ:
Как уже упоминалось в комментариях, вы можете обойти это, добавив 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>
);
}
Но это неправильно. Теперь мы говорим, что у нас есть ref
как часть реквизита, так и в качестве второго аргумента обратного вызова функции, переданной forwardRef
Моя проблема с этим, вероятно, будет яснее, если я напишу это так 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:
Вот связанный вопрос
Typescript RefForwardingComponent не работает
РЕДАКТИРОВАТЬ 3:
Я нашел соответствующий исходный код. 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>>;
Таким образом, функция forwardRef
возвращает компонент типа ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>
. Это компонент, который принимает реквизиты типа PropsWithoutRef<P>
, пересекающиеся с RefAttributes<T>
. Оба типа также определены в одном и том же файле.
Из того, что я понимаю, первый тип в основном просто исключает ref
из P (что в моем исходном примере Props
). Второй определяется как
interface RefAttributes<T> extends Attributes {
ref?: Ref<T>;
}
Учитывая эту информацию, я действительно не понимаю, почему я должен добавить ref
к своему собственному Props
. Это действительно выглядит так, как будто forwardRef
должен сделать это для меня - даже до того, что я действительно удалил ref
из моего собственного Props
...
Может кто-нибудь объяснить, что здесь происходит?