جاوااسکریپت - چگونه forwardRef را با ForwardRefRenderFunction صادر کنیم


من یک مؤلفه دارم که به یک کتابخانه رابط کاربری تعلق دارد، بگذارید آن را مؤلفه ورودی بنامیم. هنگام استفاده از این کتابخانه برای فراخوانی ورودی، انواع زیادی وجود دارد که میتوانم فراخوانی کنم. برای مثال

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

حالا میخواهم یک پوشاننده برای این کامپوننت ورودی بنویسم، پس من اینطور مینویسم

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;

در index.tsx

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

سپس میتوانم از آنها به این صورت استفاده کنم:

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

اما با انجام این کار، نمیتوانم از متدهای ref لایبرری اصلی رابط کاربری استفاده کنم (چیزهایی مثل inputRef.current.focus()). به همین دلیل از forwardRef و ForwardRefRenderFunction به این شکل استفاده میکنم

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);

با تغییر به این، میتوانم رفرنس را به کتابخانه UI اصلی پاس بدهم و از متدهای اصلی آن استفاده کنم. با این حال، مشکل من در حال حاضر این است که وقتی به forwardRef و ForwardRefRenderFunction تغییر میکنم، دیگر نمیتوانم TextArea و Search را صدا بزنم

<InputWrapper />. --> Works
<InputWrapper.TextArea />. --> Error
<InputWrapper.Search />. --> 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.

آیا کسی میتواند به من در این مورد راهنمایی کند؟ ممنون

پاسخ شماره ۱

من در نهایت از ForwardRefExoticComponent به جای ForwardRefRenderFunction استفاده میکنم

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

اما من واقعاً مطمئن نیستم تفاوت بین آنها چیست

بهروزرسانی: لطفاً پاسخ پیتر را بررسی کنید.

برای دانستن تفاوت بین این دو، لطفاً پاسخ او را اینجا بررسی کنید: تفاوت بین ForwardRefExoticComponent و ForwardRefRenderFunction در React چیست؟

پاسخ شماره ۲

کاری که تو انجام میدهی این است:

  1. تابع InputWrapper را به عنوان نوع InputWrapperComponent تعریف کنید
  2. تعریف Search و TextArea به عنوان اعضای InputWrapper
  3. یک کامپوننت ارجاعی با forwardRef ایجاد کنید

مشکل این است که forwardRef یک کامپوننت کاملاً جدید ایجاد میکند و اهمیتی نمیدهد که آیا قبلاً برخی زیرکامپوننتها تعریف شدهاند یا نه. آنها به سادگی حذف میشوند و شما خطای تعریفنشده بودن آن اعضا را دریافت میکنید.

پس راهی که باید رفت در واقع این است:

  1. تابع InputWrapper را به عنوان نوع InputWrapperComponent تعریف کنید
  2. یک کامپوننت ارجاعی با forwardRef ایجاد کنید
  3. تعریف کنید Search و TextArea به عنوان اعضای کامپوننت جدید با فوروارد کردن ref