JSX.Element बनाम ReactNode बनाम ReactElement का उपयोग कब करें?


167

मैं वर्तमान में टाइपस्क्रिप्ट के लिए एक रिएक्ट एप्लिकेशन को माइग्रेट कर रहा हूं। अब तक, यह बहुत अच्छी तरह से काम करता है, लेकिन मुझे renderअपने फ़ंक्शन घटकों के क्रमशः मेरे कार्यों के रिटर्न प्रकारों के साथ एक समस्या है ।

अब तक, मैंने हमेशा JSX.Elementरिटर्न टाइप के रूप में उपयोग किया था , अब यह किसी भी अधिक काम नहीं करता है यदि कोई घटक किसी भी चीज़ को रेंडर नहीं करने का निर्णय लेता है , यानी रिटर्न null, क्योंकि nullकोई मान्य मूल्य नहीं है JSX.Element। यह मेरी यात्रा की शुरुआत थी, क्योंकि अब मैंने वेब खोजा और पाया कि आपको ReactNodeइसके बजाय उपयोग करना चाहिए , जिसमें nullकुछ और चीजें भी शामिल हैं जो हो सकती हैं। यह बेहतर दांव लग रहा था।

हालाँकि, अब एक फंक्शन कंपोनेंट बनाते समय टाइपस्क्रिप्ट ReactNodeटाइप के बारे में शिकायत करता है । फिर, कुछ खोज के बाद, मैंने पाया कि फ़ंक्शन घटकों के लिए आपको ReactElementइसके बजाय उपयोग करना चाहिए । हालाँकि, यदि मैं ऐसा करता हूं, तो संगतता समस्या दूर हो जाती है, लेकिन अब टाइपस्क्रिप्ट पुनः nullवैध मूल्य नहीं होने के बारे में शिकायत करता है।

इसलिए, एक लंबी कहानी को छोटा करने के लिए, मेरे पास तीन प्रश्न हैं:

  1. और JSX.Element, के बीच अंतर क्या है ?ReactNodeReactElement
  2. क्यों renderवर्ग घटकों के तरीकों वापसी ReactNode, लेकिन समारोह घटकों वापसी ReactElement?
  3. मैं इसे सम्मान के साथ कैसे हल करूं null?

1
मुझे आश्चर्य है कि यह सामने आएगा, क्योंकि आमतौर पर आपको घटकों के साथ वापसी प्रकार निर्दिष्ट करने की आवश्यकता नहीं होती है। आप घटकों के लिए किस प्रकार के हस्ताक्षर कर रहे हैं? class Example extends Component<ExampleProps> {कक्षाओं के लिए और const Example: FunctionComponent<ExampleProps> = (props) => {फ़ंक्शन घटकों के लिए कुछ ऐसा दिखना चाहिए (जहां ExamplePropsअपेक्षित सहारा के लिए एक इंटरफ़ेस है)। और फिर इन प्रकारों में पर्याप्त जानकारी है कि वापसी प्रकार का अनुमान लगाया जा सकता है।
निकोलस टॉवर

यहाँ प्रकार परिभाषित किए गए हैं
जोनास विल्म्स

1
@NicholasTower हमारे लाइनिंग नियम स्पष्ट रूप से रिटर्न प्रकार प्रदान करने को लागू करते हैं, और यही कारण है कि यह आता है (जो IMHO एक अच्छी बात है, क्योंकि आपको लगता है कि आप जो करते हैं उसके बारे में अधिक सोचते हैं, जो समझने में मदद करता है, जैसे कि आप सिर्फ संकलक को सब कुछ करने देते हैं) ।
गोलो रोडेन

पर्याप्त रूप से, मैं नियमों के बारे में नहीं सोचता था।
निकोलस टॉवर

@JonasWilms लिंक के लिए धन्यवाद, लेकिन मुझे नहीं लगता कि यह मेरे सवालों का जवाब देता है।
गोलो रोडेन

जवाबों:


180

JSX.Element, ReactNode और ReactElement में क्या अंतर है?

एक ReactElement एक प्रकार और सहारा के साथ एक वस्तु है।

 interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
    type: T;
    props: P;
    key: Key | null;
}

एक ReactNode एक ReactElement, एक ReactFragment, एक स्ट्रिंग, एक संख्या या ReactNodes की एक सरणी, या अशक्त, या अपरिभाषित, या एक बूलियन है:

type ReactText = string | number;
type ReactChild = ReactElement | ReactText;

interface ReactNodeArray extends Array<ReactNode> {}
type ReactFragment = {} | ReactNodeArray;

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

JSX.Element एक ReactElement है, जिसमें प्रॉप्स के लिए जेनेरिक प्रकार और कोई भी प्रकार है। यह मौजूद है, क्योंकि विभिन्न पुस्तकालय JSX को अपने तरीके से लागू कर सकते हैं, इसलिए JSX एक वैश्विक नामस्थान है जो तब पुस्तकालय द्वारा निर्धारित किया जाता है, रिएक्ट इसे इस तरह सेट करता है:

declare global {
  namespace JSX {
    interface Element extends React.ReactElement<any, any> { }
  }
}

उदाहरण द्वारा:

 <p> // <- ReactElement = JSX.Element
   <Custom> // <- ReactElement = JSX.Element
     {true && "test"} // <- ReactNode
  </Custom>
 </p>

क्लास घटकों के रेंडर तरीके ReactNode को क्यों लौटाते हैं, लेकिन फ़ंक्शन घटक ReactElement को वापस करते हैं?

दरअसल, वे अलग चीजें लौटाते हैं। Componentएस रिटर्न:

 render(): ReactNode;

और कार्य "स्टेटलेस घटक" हैं:

 interface StatelessComponent<P = {}> {
    (props: P & { children?: ReactNode }, context?: any): ReactElement | null;
    // ... doesn't matter
}

यह वास्तव में ऐतिहासिक कारणों से है

अशक्त होने के संबंध में मैं इसे कैसे हल करूं?

इसे वैसे ReactElement | nullही लिखें जैसे प्रतिक्रिया करता है। या टाइपस्क्रिप्ट टाइप करने दें।

प्रकारों के लिए स्रोत


विस्तृत उत्तर के लिए धन्यवाद! यह पूरी तरह से प्रश्न 1 का उत्तर देता है, लेकिन फिर भी 2 और 3 अनुत्तरित प्रश्नों को छोड़ देता है। क्या आप उन पर कुछ मार्गदर्शन कर सकते हैं, कृपया, कृपया?
गोलो रोडेन

@goloRoden यकीन है, मैं अभी थोड़ा थक गया हूं और मोबाइल पर टाइप के माध्यम से स्क्रॉल करने में कुछ समय लगता है ...;)
जोनास विल्म्स

हाय @JonasWilms। के बारे में "वे नहीं करते हैं। ReactComponent को इस रूप में परिभाषित किया गया है: रेंडर (): JSX.Element | n | false?", आप कहाँ देख रहे हैं? ऐसा लगता है कि यह मेरे लिए ReactNode लौटाता है ( github.com/DefinitelyTyped/DefinitelyTyped/blob/… ) इसके अलावा मामूली टाइपो, मुझे लगता है कि ReactComponentहोना चाहिए React.Componentया Component
मार्क डोलिनर

@MarkDoliner अजीब, मैं कसम खा सकता हूं कि मैंने उस प्रकार की फ़ाइल से कॉपी की है ... जो भी हो, आप पूरी तरह से सही हैं, मैं संपादित करूंगा
जोनास विलम्स

दोस्तों क्या वेब पर कहीं भी प्रतिक्रिया और& टाइपस्क्रिप्ट का कोई आधिकारिक दस्तावेज है?
गोरान_क्लिक_इलके

30

1.) JSX.Element, ReactNode और ReactElement में क्या अंतर है?

ReactElement और JSX.ElementReact.createElement सीधे या JSX ट्रांसप्लिकेशन के माध्यम से लागू करने का परिणाम है । यह एक वस्तु है type, propsऔर keyJSX.Elementहै ReactElement, जिनके propsऔर typeप्रकार हैं any, इसलिए वे कमोबेश एक जैसे हैं।

const jsx = <div>hello</div>
const ele = React.createElement("div", null, "hello");

ReactNode का उपयोग render()क्लास के घटकों के लिए रिटर्न टाइप के रूप में किया जाता है । यह भी childrenविशेषता के लिए डिफ़ॉल्ट प्रकार है PropsWithChildren

const Comp: FunctionComponent = props => <div>{props.children}</div> 
// children?: React.ReactNode

यह प्रतिक्रिया प्रकार की घोषणाओं में अधिक जटिल लगता है , लेकिन इसके बराबर है:

type ReactNode = {} | null | undefined;
// super type `{}` has absorbed *all* other types, which are sub types of `{}`
// so it is a very "broad" type (I don't want to say useless...)

आप लगभग सब कुछ असाइन कर सकते हैं ReactNode। मैं आमतौर पर मजबूत प्रकारों को प्राथमिकता देता हूं, लेकिन इसका उपयोग करने के लिए कुछ वैध मामले हो सकते हैं।


2.) क्लास घटकों के रेंडर तरीके ReactNode को क्यों लौटाते हैं, लेकिन फ़ंक्शन घटक ReactElement को वापस करते हैं?

tl; dr: यह एक मौजूदा टीएस प्रकार की असंगति है जो कोर रिएक्ट से संबंधित नहीं है

  • टीएस वर्ग घटक: रिएक्ट / जेएस की तुलना में अधिक अनुमेय के ReactNodeसाथ रिटर्न करता हैrender()

  • टीएस फ़ंक्शन घटक: रिटर्न JSX.Element | null, रिएक्ट / जेएस से अधिक प्रतिबंधात्मक

सिद्धांत रूप में, render()रिएक्ट / जेएस वर्ग घटकों में फ़ंक्शन घटक के समान ही रिटर्न प्रकार का समर्थन करता है । टीएस के संबंध में, विभिन्न प्रकार एक प्रकार की असंगति है जो अभी भी ऐतिहासिक कारणों और पश्च-संगतता की आवश्यकता के कारण रखी गई है।

आदर्श रूप से एक वैध वापसी प्रकार संभवतः इस तरह दिखाई देगा:

type ComponentReturnType = ReactElement | Array<ComponentReturnType> | string | number 
  | boolean | null // Note: undefined is invalid

3.) मैं अशक्त होने के संबंध में इसे कैसे हल करूं?

कुछ विकल्प:
// Use type inference; inferred return type is `JSX.Element | null`
const MyComp1 = ({ condition }: { condition: boolean }) =>
    condition ? <div>Hello</div> : null

// Use explicit function return types; Add `null`, if needed
const MyComp2 = (): JSX.Element => <div>Hello</div>; 
const MyComp3 = (): React.ReactElement => <div>Hello</div>;  
// Option 3 is equivalent to 2 + we don't need to use a global (JSX namespace)

// Use built-in `FunctionComponent` or `FC` type
const MyComp4: React.FC<MyProps> = () => <div>Hello</div>;

नोट: परहेज आपको रिटर्न प्रकार प्रतिबंध से React.FC नहीं बचाएगाJSX.Element | null

रीऐक्ट ऐप बनाएं जो हाल ही में अपने टेम्प्लेट से गिराReact.FC है, क्योंकि इसमें कुछ निहितार्थ जैसे कि एक निहितार्थ है {children?: ReactNode}। तो React.FCसंयम का उपयोग करना बेहतर हो सकता है।

किनारे के मामलों में, आप वर्कअराउंड के रूप में एक प्रकार का अभिकथन या अंश जोड़ सकते हैं:
const MyCompFragment: FunctionComponent = () => <>"Hello"</>
const MyCompCast: FunctionComponent = () => "Hello" as any 
// alternative to `as any`: `as unknown as JSX.Element | null`
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.