วิธีการส่งออก forwardRef ด้วย ForwardRefRenderFunction

Oct 06 2020

ฉันมีส่วนประกอบที่เป็นของไลบรารี UI ให้เรียกมันว่าส่วนประกอบอินพุต เมื่อใช้ไลบรารีนี้เพื่อเรียก Input มีหลายประเภทที่ฉันสามารถเรียกได้ ตัวอย่างเช่น

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

ตอนนี้ฉันต้องการเขียน wrapper ให้กับส่วนประกอบ Input นี้ดังนั้นฉันจึงเขียนแบบนี้

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

แต่ด้วยการทำเช่นนี้ฉันไม่สามารถใช้วิธีการอ้างอิงของไลบรารี UI ดั้งเดิมได้ (บางอย่างเช่น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.

ใครสามารถให้คำแนะนำเกี่ยวกับเรื่องนี้ได้บ้าง ขอบคุณ

คำตอบ

1 PeterLehnhardt Oct 07 2020 at 07:23

สิ่งที่คุณกำลังทำคือ:

  1. กำหนดฟังก์ชันInputWrapperเป็นประเภทInputWrapperComponent
  2. กำหนดSearchและTextAreaเป็นสมาชิกของInputWrapper
  3. สร้างส่วนประกอบการส่งต่ออ้างอิงด้วย forwardRef

ปัญหาคือforwardRefสร้างส่วนประกอบใหม่ทั้งหมดและไม่สนใจว่าเคยมีการกำหนดส่วนประกอบย่อยมาก่อนหรือไม่ พวกเขาจะถูกโยนทิ้งไปและคุณจะได้รับข้อผิดพลาดของสมาชิกที่ไม่ได้กำหนด

วิธีที่จะไปคือ:

  1. กำหนดฟังก์ชันInputWrapperเป็นประเภทInputWrapperComponent
  2. สร้างส่วนประกอบการส่งต่ออ้างอิงด้วย forwardRef
  3. กำหนดSearchและTextAreaเป็นสมาชิกขององค์ประกอบการส่งต่ออ้างอิงใหม่
1 JakeLam Oct 07 2020 at 05:32

ฉันลงเอยด้วยการใช้ ForwardRefExoticComponent แทน ForwardRefRenderFunction

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

แต่ฉันไม่แน่ใจจริงๆว่ามันแตกต่างกันอย่างไร

อัปเดต : โปรดตรวจสอบคำตอบของ Peter

อะไรคือความแตกต่างระหว่างทั้งสองโปรดตรวจสอบคำตอบของเขาที่นี่: อะไรคือความแตกต่างระหว่าง ForwardRefExoticComponent และ ForwardRefRenderFunction ในการตอบสนอง