React.js: एक घटक को दूसरे में लपेटना


187

कई टेम्प्लेट भाषाओं में "स्लॉट्स" या "यील्ड" स्टेटमेंट्स होते हैं, जो एक टेम्पलेट को दूसरे के अंदर लपेटने के लिए कुछ प्रकार के नियंत्रण को उलटने की अनुमति देते हैं।

कोणीय में "ट्रांसक्लूड" विकल्प है

रेलों में उपज का विवरण है । यदि React.js में उपज कथन था, तो यह इस तरह दिखेगा:

var Wrapper = React.createClass({
  render: function() {
    return (
      <div className="wrapper">
        before
          <yield/>
        after
      </div>
    );
  }
});

var Main = React.createClass({
  render: function() {
    return (
      <Wrapper><h1>content</h1></Wrapper>
    );
  }
});

वांछित उत्पादन:

<div class="wrapper">
  before
    <h1>content</h1>
  after
</div>

काश, React.js एक नहीं है <yield/>। उसी आउटपुट को प्राप्त करने के लिए मैं रैपर घटक को कैसे परिभाषित करूं?


जवाबों:


245

प्रयत्न:

var Wrapper = React.createClass({
  render: function() {
    return (
      <div className="wrapper">
        before
          {this.props.children}
        after
      </div>
    );
  }
});

एकाधिक घटक देखें : बच्चे और प्रकार के बच्चे अधिक जानकारी के लिए डॉक्स में सहारा लेते हैं।


8
या आप एक उच्च क्रम के घटक का उपयोग कर सकते हैं :) stackoverflow.com/a/31564812/82609
सेबस्टियन लोरर

159

का उपयोग करते हुए children

const Wrapper = ({children}) => (
  <div>
    <div>header</div>
    <div>{children}</div>
    <div>footer</div>
  </div>
);

const App = ({name}) => <div>Hello {name}</div>;

const WrappedApp = ({name}) => (
  <Wrapper>
    <App name={name}/>
  </Wrapper>
);

render(<WrappedApp name="toto"/>,node);

इसे transclusionएंगुलर के नाम से भी जाना जाता है।

childrenप्रतिक्रिया में एक विशेष प्रोप है और इसमें आपके घटक के टैग के अंदर क्या है (यहां <App name={name}/>अंदर है Wrapper, इसलिए यह है)children

ध्यान दें कि आपको आवश्यक रूप से उपयोग करने की आवश्यकता नहीं है children, जो एक घटक के लिए अद्वितीय है, और आप चाहें तो सामान्य प्रॉप्स का भी उपयोग कर सकते हैं या प्रॉप्स और बच्चों को मिला सकते हैं:

const AppLayout = ({header,footer,children}) => (
  <div className="app">
    <div className="header">{header}</div>
    <div className="body">{children}</div>
    <div className="footer">{footer}</div>
  </div>
);

const appElement = (
  <AppLayout 
    header={<div>header</div>}
    footer={<div>footer</div>}
  >
    <div>body</div>
  </AppLayout>
);

render(appElement,node);

यह कई usecases के लिए सरल और ठीक है, और मैं इसे अधिकांश उपभोक्ता ऐप्स के लिए सुझाऊंगा।


प्रस्तुत करना

किसी घटक को रेंडर फ़ंक्शंस पास करना संभव है, इस पैटर्न को आम तौर पर कहा जाता है render prop, और childrenउस कॉलबैक को प्रदान करने के लिए अक्सर प्रोप का उपयोग किया जाता है।

यह पैटर्न वास्तव में लेआउट के लिए नहीं है। आवरण घटक का उपयोग आमतौर पर कुछ राज्य को रखने और प्रबंधित करने के लिए किया जाता है और इसे अपने रेंडर कार्यों में इंजेक्ट किया जाता है।

काउंटर उदाहरण:

const Counter = () => (
  <State initial={0}>
    {(val, set) => (
      <div onClick={() => set(val + 1)}>  
        clicked {val} times
      </div>
    )}
  </State>
); 

आप और भी अधिक फैंसी प्राप्त कर सकते हैं और एक वस्तु भी प्रदान कर सकते हैं

<Promise promise={somePromise}>
  {{
    loading: () => <div>...</div>,
    success: (data) => <div>{data.something}</div>,
    error: (e) => <div>{e.message}</div>,
  }}
</Promise>

ध्यान दें कि आपको उपयोग करने की आवश्यकता नहीं है children, यह स्वाद / एपीआई का मामला है।

<Promise 
  promise={somePromise}
  renderLoading={() => <div>...</div>}
  renderSuccess={(data) => <div>{data.something}</div>}
  renderError={(e) => <div>{e.message}</div>}
/>

आज तक, कई पुस्तकालय रेंडर प्रॉप्स (प्रतिक्रिया संदर्भ, प्रतिक्रिया-गति, अपोलो ...) का उपयोग कर रहे हैं क्योंकि लोग इस एपीआई को एचओसी की तुलना में अधिक आसान पाते हैं। प्रतिक्रिया-पॉवरप्लग सरल रेंडर-प्रोप घटकों का एक संग्रह है। प्रतिक्रिया-अपनाने से आपको रचना करने में मदद मिलती है।


उच्च-क्रम के घटक (HOC)।

const wrapHOC = (WrappedComponent) => {
  class Wrapper extends React.PureComponent {
    render() {
      return (
        <div>
          <div>header</div>
          <div><WrappedComponent {...this.props}/></div>
          <div>footer</div>
        </div>
      );
    }  
  }
  return Wrapper;
}

const App = ({name}) => <div>Hello {name}</div>;

const WrappedApp = wrapHOC(App);

render(<WrappedApp name="toto"/>,node);

एक उच्च-आदेश घटक / HOC आम तौर पर एक फ़ंक्शन होता है जो एक घटक लेता है और एक नया घटक देता है।

हायर-ऑर्डर कंपोनेंट का उपयोग करने की तुलना में अधिक प्रदर्शनकारी हो सकता है childrenया render props, क्योंकि आवरण में शॉर्ट-सर्किट करने की क्षमता हो सकती है जिससे रेंडरिंग एक कदम आगे निकल जाए shouldComponentUpdate

यहां हम उपयोग कर रहे हैं PureComponent। ऐप को री-रेंडर करते समय, यदि WrappedAppनाम प्रोप समय के साथ नहीं बदलता है, तो रैपर में यह कहने की क्षमता होती है कि "मुझे प्रस्तुत करने की आवश्यकता नहीं है क्योंकि प्रॉप्स (वास्तव में, नाम) पहले की तरह ही हैं"। childrenऊपर आधारित समाधान के साथ , भले ही आवरण हो PureComponent, यह मामला नहीं है क्योंकि बच्चों के तत्व को हर बार माता-पिता प्रदान करते हैं, जिसका अर्थ है कि आवरण हमेशा शुद्ध होगा, भले ही लिपटे घटक शुद्ध हो। एक बैबल प्लगइन है जो इसे कम करने और childrenसमय के साथ एक निरंतर तत्व सुनिश्चित करने में मदद कर सकता है ।


निष्कर्ष

उच्च-क्रम के घटक आपको बेहतर प्रदर्शन दे सकते हैं। यह इतना जटिल नहीं है, लेकिन यह निश्चित रूप से पहली बार में अविश्वसनीय लगता है।

इसे पढ़ने के बाद अपने पूरे कोडबेस को HOC पर माइग्रेट न करें। बस याद रखें कि अपने ऐप के महत्वपूर्ण रास्तों पर आप प्रदर्शन कारणों से रनटाइम रैपरों के बजाय HOCs का उपयोग करना चाह सकते हैं, खासकर यदि उसी आवरण का उपयोग कई बार किया जाए तो यह HOC बनाने पर विचार करने लायक होता है।

Redux पहले एक रनटाइम रैपर पर इस्तेमाल होता था <Connect>और बाद में connect(options)(Comp)प्रदर्शन कारणों से HOC में बदल जाता था (डिफ़ॉल्ट रूप से, रैपर शुद्ध और उपयोग होता है shouldComponentUpdate)। इस उत्तर में मैं जो प्रकाश डालना चाहता था, उसका सही चित्रण है।

ध्यान दें कि यदि किसी कंपोनेंट में रेंडर-प्रोप एपीआई है, तो आमतौर पर उसके ऊपर एक एचओसी बनाना आसान होता है, इसलिए यदि आप एक कार्यकारी लेखक हैं, तो आपको पहले रेंडर प्रोप एपीआई लिखना चाहिए, और अंततः एचओसी संस्करण की पेशकश करनी चाहिए। यह वही है जो अपोलो <Query>रेंडर-प्रोप घटक के साथ करता है , और graphqlएचओसी इसका उपयोग करता है।

व्यक्तिगत रूप से, मैं दोनों का उपयोग करता हूं, लेकिन जब संदेह होता है तो मैं HOC पसंद करता हूं क्योंकि:

  • प्रॉपर compose(hoc1,hoc2)(Comp)रेंडर करने की तुलना में उन्हें ( ) कंपोज करना ज्यादा मुहावरेदार है
  • यह मुझे बेहतर प्रदर्शन दे सकता है
  • मैं प्रोग्रामिंग की इस शैली से परिचित हूं

मैं अपने पसंदीदा टूल के HOC संस्करणों का उपयोग / निर्माण करने में संकोच नहीं करता:

  • प्रतिक्रिया का Context.ConsumerCOMP
  • अनकहा की Subscribe
  • प्रोप प्रस्तुत graphqlकरने के बजाय अपोलो के एचओसी का उपयोग करनाQuery

मेरी राय में, कभी-कभी रेंडर प्रॉप्स कोड को अधिक पठनीय बनाते हैं, कभी-कभी कम भी ... मैं अपने पास मौजूद बाधाओं के अनुसार सबसे व्यावहारिक समाधान का उपयोग करने की कोशिश करता हूं। कभी-कभी प्रदर्शन की तुलना में पठनीयता अधिक महत्वपूर्ण होती है, कभी-कभी नहीं। बुद्धिमानी से चुनें और सब कुछ रेंडर-प्रॉप में परिवर्तित करने के 2018 की प्रवृत्ति का पालन न करें।


1
यह दृष्टिकोण बच्चों के घटक (इस मामले में हैलो) को सहारा नीचे पारित करना आसान बनाता है। रिएक्ट 0.14 से। * इसके बाद बच्चों के घटकों के लिए प्रॉपर पास करने का एकमात्र तरीका React.createClone का उपयोग करना होगा, जो महंगा हो सकता है।
मुकेश सोनी

2
प्रश्न: उत्तर में "बेहतर प्रदर्शन" का उल्लेख है - जो मुझे समझ में नहीं आता है: किस अन्य समाधान की तुलना में बेहतर है?
फिलिप

1
HOCs के रनटाइम रैपरों की तुलना में बेहतर प्रदर्शन हो सकता है, क्योंकि वे पहले से रेंडरिंग को शॉर्ट-सर्किट कर सकते हैं।
सेबेस्टियन लॉर्बर

1
धन्यवाद! यह ऐसा है जैसे आपने मेरे महीने से शब्द लिए लेकिन आप उन्हें अधिक प्रतिभा के साथ व्यक्त करते हैं
K

1
यह एक बेहतर उत्तर है:] धन्यवाद!
cullanrocks

31

सोफी के जवाब के अलावा, मुझे चाइल्ड कंपोनेंट टाइप्स में भेजने का उपयोग भी मिला, कुछ इस तरह से:

var ListView = React.createClass({
    render: function() {
        var items = this.props.data.map(function(item) {
            return this.props.delegate({data:item});
        }.bind(this));
        return <ul>{items}</ul>;
    }
});

var ItemDelegate = React.createClass({
    render: function() {
        return <li>{this.props.data}</li>
    }
});

var Wrapper = React.createClass({    
    render: function() {
        return <ListView delegate={ItemDelegate} data={someListOfData} />
    }
});

2
मैंने कोई दस्तावेज नहीं देखा है delegate, आपने इसे कैसे पाया?
एनवीआई

4
आप एक घटक के लिए जो भी प्रॉप्स चाहते हैं उन्हें जोड़ सकते हैं और उन्हें नाम दे सकते हैं जैसा आप चाहते हैं, इस का उपयोग करके im करें। पंक्ति 4 पर इस।
क्रि
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.