Cómo exportar forwardRef con ForwardRefRenderFunction

Oct 06 2020

Tengo un componente que pertenece a una biblioteca de UI, llamémoslo componente de entrada. Al usar esta biblioteca para llamar a Input, hay muchos tipos a los que puedo llamar. Por ejemplo

<Input />
<Input.TextArea />
<Input.Search />

Ahora quiero escribir un contenedor para este componente de entrada, así que escribo así

type InputWrapperComponent = FC<InputProps> & {
  Search: typeof Input.Search;
  TextArea: typeof Input.TextArea;
};

const InputWrapper: InputWrapperComponent = (props) => {
  // make some minor changes here
}

InputWrapper.Search = Input.Search;
InputWrapper.TextArea = Input.TextArea;
export default InputWrapper;

en index.tsx

export { default as InputWrapper } from './input';

Entonces puedo usarlos así:

<InputWrapper />. --> Works
<InputWrapper.TextArea />. --> Works
<InputWrapper.Search />. --> Works

Pero al hacer esto, no puedo usar métodos de referencia de la biblioteca de UI original (algo así como inputRef.current.focus()). es por eso que uso forwardRef y ForwardRefRenderFunction así

type InputWrapperComponent = ForwardRefRenderFunction<HTMLInputElement, InputProps> & {
  Search: typeof Input.Search;
  TextArea: typeof Input.TextArea;
};

const InputWrapper: InputWrapperComponent = (props, ref) => {
  // make some minor changes here and add the ref to the input
}

InputWrapper.Search = Input.Search;
InputWrapper.TextArea = Input.TextArea;
export default forwardRef(InputWrapper);

Al cambiar a esto, puedo pasar la referencia a la biblioteca de UI original y puedo usar sus métodos originales. Sin embargo, mi problema en este momento es cuando cambio a forwardRef y ForwardRefRenderFunction , no puedo llamar TextArea y Portada Buscar más

<InputWrapper />. --> Works
<InputWrapper.TextArea />. --> Error
<InputWrapper.Search />. --> Error

Este es el error:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

¿Alguien puede darme alguna orientación sobre esto? Gracias

Respuestas

1 PeterLehnhardt Oct 07 2020 at 07:23

Lo que estas haciendo es:

  1. Definir función InputWrappercomo tipoInputWrapperComponent
  2. Definir Searchy TextAreacomo miembros deInputWrapper
  3. Cree un componente de reenvío de referencias con forwardRef

El problema es que eso forwardRefcrea un componente completamente nuevo y no le importa si se han definido antes algunos subcomponentes. Simplemente se desecharán y obtendrá el error de que esos miembros no están definidos.

Entonces, el camino a seguir es en realidad:

  1. Definir función InputWrappercomo tipoInputWrapperComponent
  2. Cree un componente de reenvío de referencias con forwardRef
  3. Definir Searchy TextAreacomo miembros del nuevo componente de reenvío de referencias
1 JakeLam Oct 07 2020 at 05:32

Termino usando ForwardRefExoticComponent en lugar de ForwardRefRenderFunction

type InputWrapperComponent = React.ForwardRefExoticComponent<
  React.PropsWithoutRef<InputProps> & React.RefAttributes<HTMLInputElement>
> & {
  Search: typeof Input.Search;
  TextArea: typeof Input.TextArea;
  Password: typeof Input.Password;
};

Pero realmente no estoy seguro de cuál es la diferencia entre ellos

Actualización : compruebe la respuesta de Peter.

Para saber cuál es la diferencia entre los dos, verifique su respuesta aquí: ¿ Cuál es la diferencia entre ForwardRefExoticComponent y ForwardRefRenderFunction en react?