จะใช้ลูกกับ React Stateless Functional Component ใน TypeScript ได้อย่างไร


88

การใช้ TypeScript กับ React เราไม่จำเป็นต้องขยายอีกต่อไปReact.Propsเพื่อให้คอมไพเลอร์รู้ว่าอุปกรณ์ประกอบฉากส่วนประกอบปฏิกิริยาทั้งหมดสามารถมีลูกได้:

interface MyProps { }

class MyComponent extends React.Component<MyProps, {}> {
  public render(): JSX.Element {
    return <div>{this.props.children}</div>;
  }
}

อย่างไรก็ตามดูเหมือนว่าจะไม่ใช่กรณีสำหรับส่วนประกอบการทำงานที่ไร้สถานะ:

const MyStatelessComponent = (props: MyProps) => {
  return (
    <div>{props.children}</div>
  );
};

แสดงข้อผิดพลาดในการคอมไพล์:

ข้อผิดพลาด: (102, 17) TS2339: ไม่มีคุณสมบัติ 'ลูก' ในประเภท 'MyProps'

ฉันเดาว่านี่เป็นเพราะไม่มีทางที่คอมไพเลอร์จะรู้ว่าฟังก์ชันวานิลลาจะได้รับchildrenในอาร์กิวเมนต์อุปกรณ์ประกอบฉาก

คำถามคือเราจะใช้ลูกในองค์ประกอบการทำงานที่ไร้สัญชาติใน TypeScript ได้อย่างไร?

ฉันสามารถกลับไปใช้วิธีเดิมMyProps extends React.Propsได้ แต่Propsอินเทอร์เฟซถูกทำเครื่องหมายว่าเลิกใช้งานแล้วและส่วนประกอบที่ไม่มีสถานะไม่มีหรือรองรับ a Props.refตามที่ฉันเข้าใจ

ดังนั้นฉันสามารถกำหนดchildrenเสาด้วยตนเอง:

interface MyProps {
  children?: React.ReactNode;
}

อันดับแรก: เป็นReactNodeประเภทที่ถูกต้องหรือไม่?

ประการที่สอง: ฉันต้องเขียนเด็กเป็นตัวเลือก ( ?) ไม่เช่นนั้นผู้บริโภคจะคิดว่าสิ่งchildrenนั้นควรเป็นแอตทริบิวต์ขององค์ประกอบ ( <MyStatelessComponent children={} />) และเพิ่มข้อผิดพลาดหากไม่ได้ระบุค่าไว้

ดูเหมือนว่าฉันจะขาดอะไรไป ใครสามารถให้ความชัดเจนได้บ้างว่าตัวอย่างสุดท้ายของฉันเป็นวิธีใช้ส่วนประกอบที่ใช้งานได้แบบไม่ระบุสถานะกับลูก ๆ ใน React หรือไม่?

คำตอบ:


89

ตอบสนองการอัปเดต 16.8: ตั้งแต่ React 16.8 ชื่อReact.SFCและReact.StatelessComponentเลิกใช้งาน จริงๆแล้วพวกเขากลายเป็นนามแฝงสำหรับReact.FunctionComponentประเภทหรือReact.FCสั้น ๆ

คุณจะใช้มันในลักษณะเดียวกันแม้ว่า:

const MyStatelessComponent : React.FunctionComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

ก่อนตอบสนอง 16.8 (เก่ากว่า):

ในตอนนี้คุณสามารถใช้React.StatelessComponent<>ประเภทดังต่อไปนี้:

const MyStatelessComponent : React.StatelessComponent<{}> = props =>
    <div>{props.children}</div>

สิ่งที่ฉันได้เพิ่มคือการตั้งค่าประเภทการส่งคืนของส่วนประกอบที่จะReact.StatelessComponentพิมพ์

สำหรับส่วนประกอบที่มีอุปกรณ์ประกอบฉากของคุณเอง (เช่นMyPropsอินเทอร์เฟซ):

const MyStatelessComponent : React.StatelessComponent<MyProps> = props =>
    <div>
        <p>{props.propInMyProps}</p>
        <p>{props.children}</p>
    </div>

ตอนนี้propsได้รับchildrenคุณสมบัติเช่นเดียวกับที่จากMyPropsอินเตอร์เฟซ

ฉันตรวจสอบสิ่งนี้ใน typescript เวอร์ชัน 2.0.7

นอกจากนี้คุณสามารถใช้React.SFCแทนReact.StatelessComponentความกะทัดรัดได้


ขอบคุณ! ดูเหมือนว่าฉันใช้ตัวพิมพ์รุ่นเก่าที่ไม่รองรับสิ่งนี้ ... ฉันเดาว่าถึงเวลาที่จะกัดกระสุนและใช้ TS 2.0 กับ@types
Aaron Beall

3
React.StatelessComponent/ React.SFCเลิกใช้งานแล้ว ขอแนะนำให้อ้างถึงReact.FunctionComponentแทน
Alexander Kachkaev

โปรดทราบว่าวิธีนี้ใช้ไม่ได้หากคุณมีส่วนประกอบทั่วไป
FunkeyFlo

94

คุณสามารถใช้React.PropsWithChildren<P>ประเภทสำหรับอุปกรณ์ประกอบฉากของคุณ:

interface MyProps { }

function MyComponent(props: React.PropsWithChildren<MyProps>) {
  return <div>{props.children}</div>;
}


0

คำตอบที่ง่ายกว่า: ใช้ReactNode:

interface MyProps {
  children?: React.ReactNode
}

ถ้าchildrenเป็นทางเลือกหรือไม่ (เช่นมี?หรือไม่) ขึ้นอยู่กับส่วนประกอบของคุณ วิธี?นี้เป็นวิธีที่กระชับที่สุดในการแสดงออกจึงไม่มีอะไรผิดปกติ

เกี่ยวกับประวัติ: นี่ไม่ใช่คำตอบที่ถูกต้องเมื่อถูกถามครั้งแรก: ประเภทReactNodeนี้ถูกเพิ่มใน (เกือบ) รูปแบบปัจจุบันในเดือนมีนาคม 2017 โดยคำขอดึงนี้เท่านั้น แต่เกือบทุกคนที่อ่านวันนี้ควรใช้ React เวอร์ชันที่ทันสมัยเพียงพอ .

สุดท้ายเกี่ยวกับการส่งchildrenเป็น "แอตทริบิวต์" (ซึ่งใน React lingo จะส่งต่อเป็น "prop" ไม่ใช่แอตทริบิวต์): เป็นไปได้ แต่ในกรณีส่วนใหญ่จะอ่านได้ดีกว่าเมื่อส่งลูก JSX:

<MyComponent>
  <p>This is part of the children.</p>
</MyComponent>

อ่านง่ายกว่า

<MyComponent children={<p>This is part of the children.</p>} />

-1

คุณสามารถเพิ่มลูกเข้าไปในส่วนประกอบและถ้าเชื่อมต่อกับคอนเทนเนอร์ที่คุณต้องการทั้งหมด

const MyComponent = ({ 
   children  
}) => {
  return <div>{children}</div>

}

ทำไมต้องเพิ่มคำตอบอื่นสำหรับคำถามเก่า ๆ แบบนี้?
Mike Szyndel

และมันเป็นคำถาม TypeScript
Zsolt Meszaros
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.