प्रॉप्स को {this.props.children} में कैसे पास करें


887

मैं कुछ घटकों को परिभाषित करने का उचित तरीका खोजने की कोशिश कर रहा हूं, जिनका उपयोग सामान्य तरीके से किया जा सकता है:

<Parent>
  <Child value="1">
  <Child value="2">
</Parent>

माता-पिता और बच्चों के घटकों के बीच प्रतिपादन के लिए एक तर्क चल रहा है, आप कल्पना कर सकते हैं <select>और <option>इस तर्क के उदाहरण के रूप में।

यह प्रश्न के उद्देश्य के लिए एक डमी कार्यान्वयन है:

var Parent = React.createClass({
  doSomething: function(value) {
  },
  render: function() {
    return (<div>{this.props.children}</div>);
  }
});

var Child = React.createClass({
  onClick: function() {
    this.props.doSomething(this.props.value); // doSomething is undefined
  },
  render: function() {
    return (<div onClick={this.onClick}></div>);
  }
});

सवाल यह है कि जब भी आप {this.props.children}एक रैपर घटक को परिभाषित करने के लिए उपयोग करते हैं, तो आप अपने सभी बच्चों को कुछ संपत्ति कैसे पास करते हैं?


जवाबों:


955

नए प्रॉप्स के साथ बच्चों को क्लोन करना

आप बच्चों पर पुनरावृति करने के लिए React.Children का उपयोग कर सकते हैं , और फिर React.cloneElement का उपयोग करके नए प्रॉप्स (उथले विलय) के साथ प्रत्येक तत्व को क्लोन कर सकते हैं :

import React, { Children, isValidElement, cloneElement } from 'react';

const Child = ({ doSomething, value }) => (
  <div onClick={() => doSomething(value)}>Click Me</div>
);

function Parent({ children }) {
  function doSomething(value) {
    console.log('doSomething called by child with value:', value);
  }

  render() {
    const childrenWithProps = Children.map(children, child => {
      // Checking isValidElement is the safe way and avoids a TS error too.
      if (isValidElement(child)) {
        return cloneElement(child, { doSomething })
      }

      return child;
    });

    return <div>{childrenWithProps}</div>
  }
};

ReactDOM.render(
  <Parent>
    <Child value="1" />
    <Child value="2" />
  </Parent>,
  document.getElementById('container')
);

फिडल: https://jsfiddle.net/2q294y43/2/

बच्चों को एक समारोह के रूप में बुलाते हुए

आप रेंडर प्रॉप्स वाले बच्चों को प्रॉप्स भी पास कर सकते हैं । इस दृष्टिकोण में बच्चे (जो childrenकिसी अन्य प्रोप नाम के हो सकते हैं ) एक ऐसा कार्य है जिसे आप किसी भी तर्क को स्वीकार कर सकते हैं जिसे आप पास करना चाहते हैं और बच्चों को लौटाना चाहते हैं:

const Child = ({ doSomething, value }) => (
  <div onClick={() =>  doSomething(value)}>Click Me</div>
);

function Parent({ children }) {
  function doSomething(value) {
    console.log('doSomething called by child with value:', value);
  }

  render() {
    // Note that children is called as a function and we can pass args to it
    return <div>{children(doSomething)}</div>
  }
};

ReactDOM.render(
  <Parent>
    {doSomething => (
      <React.Fragment>
        <Child doSomething={doSomething} value="1" />
        <Child doSomething={doSomething} value="2" />
      </React.Fragment>
    )}
  </Parent>,
  document.getElementById('container')
);

इसके बजाय <React.Fragment>या बस <>आप चाहें तो एक सरणी भी लौटा सकते हैं।

फिडल: https://jsfiddle.net/ferahl/y5pcua68/7/


7
यह मेरे लिए काम नहीं करता है। यह React.cloneElement () के भीतर परिभाषित नहीं है
पैट्रिक

12
इस उत्तर से काम नहीं करता, valueको पारित कर दिया doSomethingखो दिया है।
डेव

3
@DominicTobias Arg, क्षमा करें, मैंने कंसोल को बंद कर दिया है। अलर्ट पर जाएं और दो पैरामेट्स को एक स्ट्रिंग में सम्‍मिलित करना भूल गया।
डेव

1
यह उत्तर सुपर-सहायक था, लेकिन मैं एक ऐसे मुद्दे पर भाग गया, जिसका उल्लेख यहां नहीं किया गया है और मैं सोच रहा था कि क्या यह कोई नई चीज है जो बदल गई है या क्या यह मेरे अंत में कुछ अजीब है। जब मैंने अपने बाल तत्व को क्लोन किया, तब तक यह बच्चा पुराने तत्व पर सेट हो चुका था, जब तक कि मैंने इसे जोड़ नहीं दिया। क्लोन के क्लेमेंट के तीसरे तर्क के लिए।
एफेन

7
क्या होगा यदि बच्चा एक मार्ग (v4) के माध्यम से एक अलग रूट पृष्ठ से लोड किया जाता है?
१18

393

इसे करने के लिए थोड़ा क्लीनर तरीके के लिए, प्रयास करें:

<div>
    {React.cloneElement(this.props.children, { loggedIn: this.state.loggedIn })}
</div>

संपादित करें: कई व्यक्तिगत बच्चों के साथ उपयोग करने के लिए (बच्चे को स्वयं एक घटक होना चाहिए) जो आप कर सकते हैं। 16.8.6 में परीक्षण किया गया

<div>
    {React.cloneElement(props.children[0], { loggedIn: true, testingTwo: true })}
    {React.cloneElement(props.children[1], { loggedIn: true, testProp: false })}
</div>

10
मैं सबसे अधिक मूल्यांकन किए गए उत्तर का उपयोग कर रहा था, लेकिन यह एक बहुत सीधे आगे है! यह समाधान भी है जो वे प्रतिक्रिया-राउटर उदाहरण पृष्ठ पर उपयोग करते हैं।
कैप्टनलाइट लाइट

10
क्या कोई समझा सकता है कि यह कैसे काम करता है (या यह वास्तव में क्या करता है)? डॉक्स को पढ़ते हुए , मैं यह नहीं देख सका कि यह बच्चों में कैसे उतरेगा और प्रत्येक बच्चे के लिए उस प्रस्ताव को जोड़ देगा - क्या ऐसा करने का इरादा है? यदि ऐसा होता है, तो हम कैसे जानते हैं कि यह वही है जो यह करेगा? यह बिल्कुल स्पष्ट नहीं है कि यह एक अपारदर्शी डेटा संरचना ( this.props.children) से cloneElement... को पारित करने के लिए मान्य है जो एक ... तत्व की उम्मीद कर रहा है।
ग्रीनएजजादे

51
वास्तव में, यह एक से अधिक बच्चों के साथ काम नहीं करता है।
दनिता

17
तो आप कोड लिख सकते हैं जो काम करता है जबकि कोई केवल एक बच्चे को एक घटक में पास करता है, लेकिन जब वे एक और जोड़ते हैं, तो यह दुर्घटनाग्रस्त हो जाता है ... जो चेहरे के मूल्य के लिए महान नहीं लगता है? यह ओपी के लिए एक जाल प्रतीत होगा, जिसने विशेष रूप से सभी बच्चों को प्रॉपर पास करने के बारे में पूछा ।
ग्रीनएजजेड

10
@GreenAsJade जब तक आपका घटक एक एकल बच्चे की उम्मीद कर रहा है तब तक उसका जुर्माना लगाएं। आप अपने घटकों के माध्यम से परिभाषित कर सकते हैं कि यह एकल बच्चे की अपेक्षा करता है। React.Children.onlyफ़ंक्शन एक ही बच्चा देता है या एक अपवाद फेंकता है अगर वहाँ कई (यह मौजूद नहीं होगा अगर कोई उपयोग मामला नहीं था)।
cchamberlain

80

इसे इस्तेमाल करे

<div>{React.cloneElement(this.props.children, {...this.props})}</div>

इसने मेरे लिए प्रतिक्रिया -15.1 का उपयोग किया।


3
क्या टैग React.cloneElement()में इसे घेरे बिना सीधे लौटना संभव है <div>? क्योंकि क्या होगा यदि बच्चा एक <span>(या कुछ और) है और हम उसके टैग तत्व प्रकार को संरक्षित करना चाहते हैं?
एड्रिनमेक

1
यदि यह एक बच्चा है तो आप रैपर को छोड़ सकते हैं और यह समाधान केवल एक बच्चे के लिए काम करता है।
थेजय

1
मेरे लिये कार्य करता है। संलग्न किए बिना <div> ठीक है।
क्रैश

4
यदि आपको यह स्पष्ट रूप से लागू करने की आवश्यकता है कि आप केवल एक बच्चा प्राप्त करते हैं, तो आप वह कर सकते हैं React.cloneElement(React.Children.only(this.props.children), {...this.props})जो एक से अधिक बच्चों के पास होने पर एक त्रुटि देगा। तो फिर तुम एक div में लपेटने की जरूरत नहीं है।
इटानडेरसन

1
यह उत्तर एक TypeError: चक्रीय वस्तु मान उत्पन्न कर सकता है। जब तक आप बच्चे के प्रॉप्स में से एक को खुद नहीं चाहते, let {children, ...acyclicalProps} = this.propsतब तक उपयोग करें और फिर React.cloneElement(React.Children.only(children), acyclicalProps)
परबोलार्ड

68

सीधे बच्चों को सहारा देना।

अन्य सभी उत्तर देखें

संदर्भ के माध्यम से घटक वृक्ष के माध्यम से साझा, वैश्विक डेटा

संदर्भ को डेटा साझा करने के लिए डिज़ाइन किया गया है, जिसे रिएक्ट घटकों के एक पेड़ के लिए "वैश्विक" माना जा सकता है, जैसे कि वर्तमान प्रमाणित उपयोगकर्ता, विषय या पसंदीदा भाषा। 1

अस्वीकरण: यह एक अद्यतन उत्तर है, पिछले वाले ने पुराने संदर्भ API का उपयोग किया था

यह उपभोक्ता / प्रदान सिद्धांत पर आधारित है। सबसे पहले, अपना संदर्भ बनाएं

const { Provider, Consumer } = React.createContext(defaultValue);

फिर के माध्यम से उपयोग करें

<Provider value={/* some value */}>
  {children} /* potential consumers */
<Provider />

तथा

<Consumer>
  {value => /* render something based on the context value */}
</Consumer>

सभी उपभोक्ता जो प्रदाता के वंशज हैं, जब भी प्रदाता के मूल्य में परिवर्तन होता है, तब वे फिर से प्रस्तुत करेंगे। प्रदाता से उसके वंशज उपभोक्ताओं के लिए प्रचार ,ComComponentUpdate विधि के अधीन नहीं है, इसलिए उपभोक्ता तब भी अपडेट किया जाता है जब कोई पूर्वज घटक अपडेट से बाहर हो जाता है। 1

पूर्ण उदाहरण, अर्ध-छद्म कोड।

import React from 'react';

const { Provider, Consumer } = React.createContext({ color: 'white' });

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: { color: 'black' },
    };
  }

  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}

class Toolbar extends React.Component {
  render() {
    return ( 
      <div>
        <p> Consumer can be arbitrary levels deep </p>
        <Consumer> 
          {value => <p> The toolbar will be in color {value.color} </p>}
        </Consumer>
      </div>
    );
  }
}

1 https://facebook.github.io/react/docs/context.html


6
स्वीकृत उत्तर के विपरीत, यह तब भी ठीक से काम करेगा, जब पैरेन्ट के अंतर्गत अन्य तत्व शामिल हों। यह निश्चित रूप से सबसे अच्छा जवाब है।
ज़ाप्री

6
प्रॉप्स! = संदर्भ
पेट्र पेलर

आप संदर्भ के माध्यम से प्रचारित परिवर्तनों पर निर्भर नहीं कर सकते। जब यह संभव हो तो प्रॉप्स का प्रयोग करें।
थेजय

1
शायद मुझे समझ में नहीं आता है, लेकिन यह कहना गलत नहीं है कि "संदर्भ प्रॉप्स उपलब्ध करता है"? जब मैंने अंतिम बार संदर्भ का उपयोग किया था, तो यह एक अलग बात थी (यानी this.context) - यह जादुई रूप से संदर्भ को प्रॉप्स के साथ विलय नहीं करता था। आपको संदर्भ को जानबूझकर सेट और उपयोग करना था, जो कि पूरी तरह से दूसरी चीज है।
जोश

आप पूरी तरह से समझते हैं, यह गलत था। मैंने अपना उत्तर संपादित कर दिया है।
हासोमिर

48

नेस्टेड बच्चों को प्रॉप्स पास करना

React 16.6 के अपडेट के साथ अब आप React.createContext और ReferenceType का उपयोग कर सकते हैं ।

import * as React from 'react';

// React.createContext accepts a defaultValue as the first param
const MyContext = React.createContext(); 

class Parent extends React.Component {
  doSomething = (value) => {
    // Do something here with value
  };

  render() {
    return (
       <MyContext.Provider value={{ doSomething: this.doSomething }}>
         {this.props.children}
       </MyContext.Provider>
    );
  }
}

class Child extends React.Component {
  static contextType = MyContext;

  onClick = () => {
    this.context.doSomething(this.props.value);
  };      

  render() {
    return (
      <div onClick={this.onClick}>{this.props.value}</div>
    );
  }
}


// Example of using Parent and Child

import * as React from 'react';

class SomeComponent extends React.Component {

  render() {
    return (
      <Parent>
        <Child value={1} />
        <Child value={2} />
      </Parent>
    );
  }
}

React.createContext चमकता है जहां React.cloneElement मामला नेस्टेड घटकों को संभाल नहीं सकता है

class SomeComponent extends React.Component {

  render() {
    return (
      <Parent>
        <Child value={1} />
        <SomeOtherComp><Child value={2} /></SomeOtherComp>
      </Parent>
    );
  }
}

3
क्या आप बता सकते हैं कि क्यों => कार्य एक बुरा अभ्यास है? => फ़ंक्शन thisसंदर्भ प्राप्त करने के लिए घटना संचालकों को बांधने में मदद करता है
केनेथ ट्रूंग

@KennethTruong क्योंकि हर बार जब यह रेंडर करता है तो यह एक फंक्शन बनाता है।
itdoesntwork

9
@itdoesntwork यह सच नहीं है। यह केवल एक नया फ़ंक्शन बनाता है जब कक्षा बनाई जाती है। रेंडर फंक्शन के दौरान इसका निर्माण नहीं हो रहा है ..
केनेथ ट्रूंग

@KennethTruong reactjs.org/docs/faq-functions.html#arrow-function-in-render मुझे लगा कि आप रेंडर में एरो फंक्शन की बात कर रहे हैं।
itdoesntwork

24

आप इसका उपयोग कर सकते हैं React.cloneElement, यह जानना बेहतर है कि आपके आवेदन में इसका उपयोग शुरू करने से पहले यह कैसे काम करता है। इसे और React v0.13अधिक जानकारी के लिए, इस पर पेश किया गया है , इसलिए आपके लिए इस काम के साथ कुछ:

<div>{React.cloneElement(this.props.children, {...this.props})}</div>

तो आपके लिए यह समझने के लिए रिएक्ट डॉक्यूमेंटेशन की लाइनें लाएँ कि यह कैसे काम कर रहा है और आप उनका उपयोग कैसे कर सकते हैं:

React v0.13 RC2 में हम इस हस्ताक्षर के साथ React.addons.cloneWithProps के समान एक नया एपीआई पेश करेंगे:

React.cloneElement(element, props, ...children);

CloneWithProps के विपरीत, इस नए फ़ंक्शन में स्टाइल और क्लासनेम को मर्ज करने के लिए कोई जादू निर्मित व्यवहार नहीं होता है उसी कारण से हमारे पास ट्रांसफरप्रॉप्स से वह सुविधा नहीं है। किसी को भी यकीन नहीं है कि वास्तव में जादू की चीजों की पूरी सूची क्या है, जिससे कोड के बारे में तर्क करना मुश्किल हो जाता है और जब एक अलग हस्ताक्षर (आगामी प्रतिक्रिया मूल में जैसे) शैली का पुन: उपयोग करना मुश्किल होता है।

React.cloneElement लगभग इसके बराबर है:

<element.type {...element.props} {...props}>{children}</element.type>

हालाँकि, JSX और cloneWithProps के विपरीत, यह Refs को भी संरक्षित करता है। इसका मतलब यह है कि यदि आप इस पर एक रेफरी के साथ एक बच्चा प्राप्त करते हैं, तो आप गलती से इसे अपने पूर्वजों से चोरी नहीं करेंगे। आपको अपने नए तत्व से वही परिशोध मिलेगा।

एक सामान्य पैटर्न यह है कि आप अपने बच्चों के नक्शे पर जाएं और एक नया प्रस्ताव जोड़ें। CloneWithProps द्वारा रेफरी को खोने के बारे में कई समस्याएं बताई गईं, जिससे आपके कोड के बारे में तर्क करना मुश्किल हो गया। अब क्लोनमेंट के साथ समान पैटर्न का पालन करना उम्मीद के मुताबिक काम करेगा। उदाहरण के लिए:

var newChildren = React.Children.map(this.props.children, function(child) {
  return React.cloneElement(child, { foo: true })
});

नोट: React.cloneElement (बच्चा, {ref: 'newRef'}) रेफरी को ओवरराइड करता है, इसलिए दो माता-पिता के लिए एक ही बच्चे के लिए रेफरी होना अभी भी संभव नहीं है, जब तक कि आप कॉलबैक-रेफ का उपयोग न करें।

प्रॉक्ट 0.13 में आने के लिए यह एक महत्वपूर्ण विशेषता थी क्योंकि प्रॉप्स अब अपरिवर्तनीय हैं। अपग्रेड पथ अक्सर तत्व को क्लोन करने के लिए होता है, लेकिन ऐसा करने से आप रेफरी खो सकते हैं। इसलिए, हमें यहां एक अच्छे उन्नयन मार्ग की आवश्यकता थी। जब हम फेसबुक पर कॉल अपग्रेड कर रहे थे तब हमें महसूस हुआ कि हमें इस तरीके की जरूरत है। हमें समुदाय से समान प्रतिक्रिया मिली। इसलिए हमने यह सुनिश्चित करने के लिए अंतिम रिलीज से पहले एक और आरसी बनाने का फैसला किया कि हम इसे प्राप्त करते हैं।

हम अंततः React.addons.cloneWithProps को अपदस्थ करने की योजना बनाते हैं। हम इसे अभी तक नहीं कर रहे हैं, लेकिन यह अपने स्वयं के उपयोग के बारे में सोचना शुरू करने और इसके बजाय React.cloneElement का उपयोग करने पर विचार करने का एक अच्छा अवसर है। इससे पहले कि हम वास्तव में इसे हटा दें, ताकि कोई तत्काल कार्रवाई आवश्यक न हो, हम एक बार अवक्षेपण सूचनाओं के साथ एक रिलीज़ शिप करना सुनिश्चित करेंगे।

अधिक यहाँ ...


17

सबसे अच्छा तरीका है, जो आपको संपत्ति हस्तांतरण करने की अनुमति देता है childrenएक फ़ंक्शन की तरह है

उदाहरण:

export const GrantParent = () => {
  return (
    <Parent>
      {props => (
        <ChildComponent {...props}>
          Bla-bla-bla
        </ChildComponent>
      )}
    </Parent>
  )
}

export const Parent = ({ children }) => {
    const somePropsHere = { //...any }
    <>
        {children(somePropsHere)}
    </>
}

1
मुझे स्वीकृत उत्तर की तुलना में यह अधिक सीधा (और प्रदर्शन के लिए बेहतर?) लगता है।
शिकोयो

2
इसके लिए बच्चों को एक समारोह की आवश्यकता होती है और यह अवसादग्रस्त घटकों के लिए काम नहीं करता है
डिजिटल भ्रम

@digitalillusion, मुझे समझ में नहीं आता कि इसका क्या मतलब है nested components। प्रतिक्रिया में नेस्टेड पैटर्न नहीं होते हैं, केवल रचनाएं होती हैं। हां, बच्चों को एक फंक्शन होना चाहिए, कोई विरोध नहीं है, क्योंकि यह जेएसएक्स का वैध बच्चा है। क्या आप एक उदाहरण दे सकते हैं nesting components?
निक ओविचनिकोव

1
आप सही कह रहे हैं कि गहराई से नेस्टेड बच्चों <Parent>{props => <Nest><ChildComponent /></Nest>}</Parent>को (काम न करने) की बजाय संभाला जा सकता है, <Parent><Nest>{props => <ChildComponent />}</Nest></Parent>इसलिए मैं मानता हूं कि यह सबसे अच्छा जवाब है
डिजिटल भ्रम

प्रयास करते समय, मुझे निम्नलिखित प्राप्त होते हैं:TypeError: children is not a function
रयान प्रेंटिस

6

मैं इसे का उपयोग कर काम करने के लिए ऊपर स्वीकार किए जाते हैं जवाब को ठीक करने के लिए आवश्यक है कि के बजाय इस सूचक। मानचित्र फ़ंक्शन के दायरे में यह doSomething फ़ंक्शन को परिभाषित नहीं करता है।

var Parent = React.createClass({
doSomething: function() {
    console.log('doSomething!');
},

render: function() {
    var that = this;
    var childrenWithProps = React.Children.map(this.props.children, function(child) {
        return React.cloneElement(child, { doSomething: that.doSomething });
    });

    return <div>{childrenWithProps}</div>
}})

अपडेट: यह फिक्स ECMAScript 5 के लिए है, ES6 में var = इस में कोई आवश्यकता नहीं है


13
या बस का उपयोग करेंbind()
प्लस-

1
या एक तीर फ़ंक्शन का उपयोग करें, जो शाब्दिक गुंजाइश से बांधता है, मैंने अपना जवाब अपडेट किया
डोमिनिक

क्या होगा अगर doSomethingएक वस्तु, जैसे doSomething: function(obj) { console.log(obj) }और बच्चे में आप this.props.doSomething(obj)लॉग आउट करने के लिए कहेंगे"obj"
conor909

4
@ प्लस- मुझे पता है कि यह पुराना है, लेकिन यहाँ बाँध का उपयोग करना एक भयानक विचार है, बाँध एक नया कार्य करता है जो एक नए संदर्भ को बांधता है। मूल रूप से एक applyविधि कॉलिंग विधि। bind()रेंडर फंक्शन में उपयोग करने से रेंडर विधि कहे जाने पर हर बार एक नया फंक्शन होगा।
बमीह

6

एक या एक से अधिक बच्चों पर विचार करने का तरीका

<div>
   { React.Children.map(this.props.children, child => React.cloneElement(child, {...this.props}))}
</div>

यह मेरे लिए काम नहीं करता है, यह एक त्रुटि देता है: बच्चों को परिभाषित नहीं किया गया है।
Deelux

बच्चों के बजाय this.props.children @Deelux
मार्टिन डावसन

यह बच्चे को अपने बच्चों के रूप में पारित करता है this.props। सामान्य तौर पर मैं केवल विशिष्ट प्रॉप्स के साथ क्लोनिंग की सलाह दूंगा, न कि पूरे शेबंग के साथ।
एंडी

पासिंग {...this.props}मेरे काम नहीं आई, क्या तरीका {...child.props}सही है?
फेलिप अगस्टो

कार्यात्मक घटकों के लिए:React.Children.map(children, child => React.cloneElement(child, props))
बनाम vsync

5

कोई भी उत्तर उन बच्चों को होने के मुद्दे को संबोधित नहीं करता है जो कि प्रतिक्रियाशील घटक नहीं हैं , जैसे कि पाठ स्ट्रिंग। वर्कअराउंड कुछ इस तरह हो सकता है:

// Render method of Parent component
render(){
    let props = {
        setAlert : () => {alert("It works")}
    };
    let childrenWithProps = React.Children.map( this.props.children, function(child) {
        if (React.isValidElement(child)){
            return React.cloneElement(child, props);
        }
          return child;
      });
    return <div>{childrenWithProps}</div>

}

5

अब तुम्हारी जरूरत नहीं है {this.props.children}। अब आप का उपयोग कर अपने बच्चे घटक लपेट कर सकते हैं renderमें Routeऔर हमेशा की तरह अपने रंगमंच की सामग्री पारित:

<BrowserRouter>
  <div>
    <ul>
      <li><Link to="/">Home</Link></li>
      <li><Link to="/posts">Posts</Link></li>
      <li><Link to="/about">About</Link></li>
    </ul>

    <hr/>

    <Route path="/" exact component={Home} />
    <Route path="/posts" render={() => (
      <Posts
        value1={1}
        value2={2}
        data={this.state.data}
      />
    )} />
    <Route path="/about" component={About} />
  </div>
</BrowserRouter>

2
रेंडर प्रॉप्स अब रिएक्ट ( reactjs.org/docs/render-props.html ) में मानक हैं और इस प्रश्न के लिए एक नए स्वीकृत उत्तर के रूप में विचार करने योग्य हैं।
इयान डैनफोर्थ

19
यह सवाल का जवाब कैसे है?
मैक्सिमो डोमिंगुएज

4

Parent.jsx:

import React from 'react';

const doSomething = value => {};

const Parent = props => (
  <div>
    {
      !props || !props.children 
        ? <div>Loading... (required at least one child)</div>
        : !props.children.length 
            ? <props.children.type {...props.children.props} doSomething={doSomething} {...props}>{props.children}</props.children.type>
            : props.children.map((child, key) => 
              React.cloneElement(child, {...props, key, doSomething}))
    }
  </div>
);

Child.jsx:

import React from 'react';

/* but better import doSomething right here,
   or use some flux store (for example redux library) */
export default ({ doSomething, value }) => (
  <div onClick={() => doSomething(value)}/>
);

और main.jsx:

import React from 'react';
import { render } from 'react-dom';
import Parent from './Parent';
import Child from './Child';

render(
  <Parent>
    <Child/>
    <Child value='1'/>
    <Child value='2'/>
  </Parent>,
  document.getElementById('...')
);

यहाँ उदाहरण देखें: https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview


4

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

बाल घटक के रूप में कार्य


यह एक विरोधी प्रतिमान नहीं है: youtube.com/watch?v=BcVAq3YFiuc
Pietro Coelho

4

यदि आपके पास कई बच्चे हैं, जिन्हें आप सहारा देना चाहते हैं , तो आप इसे इस तरह से कर सकते हैं, React.Children.map का उपयोग करके:

render() {
    let updatedChildren = React.Children.map(this.props.children,
        (child) => {
            return React.cloneElement(child, { newProp: newProp });
        });

    return (
        <div>
            { updatedChildren }
        </div>
    );
}

यदि आपके घटक में सिर्फ एक बच्चा है, तो मैपिंग की कोई आवश्यकता नहीं है, आप बस सीधे क्लोन कर सकते हैं:

render() {
    return (
        <div>
            {
                React.cloneElement(this.props.children, {
                    newProp: newProp
                })
            }
        </div>
    );
}

3

के प्रलेखन के अनुसार cloneElement()

React.cloneElement(
  element,
  [props],
  [...children]
)

प्रारंभिक बिंदु के रूप में तत्व का उपयोग करके एक नया रिएक्ट तत्व क्लोन और वापस करें। परिणामी तत्व में मूल तत्व के प्रॉप्स होंगे जो उथलेपन में विलय किए गए नए प्रॉप्स के साथ होंगे। नए बच्चे मौजूदा बच्चों की जगह लेंगे। मूल तत्व से कुंजी और रेफ को संरक्षित किया जाएगा।

React.cloneElement() इसके लगभग बराबर है:

<element.type {...element.props} {...props}>{children}</element.type>

हालाँकि, यह refs को भी सुरक्षित रखता है। इसका मतलब यह है कि यदि आप इस पर एक रेफरी के साथ एक बच्चा प्राप्त करते हैं, तो आप गलती से इसे अपने पूर्वजों से चोरी नहीं करेंगे। आपको अपने नए तत्व से वही परिशोध मिलेगा।

तो क्लोनऑनमेंट वह है जो आप बच्चों को कस्टम प्रॉप प्रदान करने के लिए उपयोग करेंगे। हालांकि घटक में कई बच्चे हो सकते हैं और आपको इसके ऊपर लूप करने की आवश्यकता होगी। आपके द्वारा उपयोग किए जाने वाले मानचित्रों के लिए अन्य उत्तर क्या सुझाव देते हैं React.Children.map। हालांकि React.Children.mapविपरीत React.cloneElementपरिवर्तन तत्व की कुंजी जोड़कर और अतिरिक्त .$उपसर्ग के रूप में। अधिक विवरण के लिए इस प्रश्न को देखें: React.cloneElement अंदर React.Children.map तत्व कुंजियों को बदलने का कारण बन रहा है

यदि आप इससे बचना चाहते हैं, तो आपको इसके बजाय forEachफ़ंक्शन के लिए जाना चाहिए

render() {
    const newElements = [];
    React.Children.forEach(this.props.children, 
              child => newElements.push(
                 React.cloneElement(
                   child, 
                   {...this.props, ...customProps}
                )
              )
    )
    return (
        <div>{newElements}</div>
    )

}

2

इसके अलावा @and_rest जवाब में, यह है कि मैं बच्चों को कैसे क्लोन करता हूं और एक कक्षा जोड़ देता हूं।

<div className="parent">
    {React.Children.map(this.props.children, child => React.cloneElement(child, {className:'child'}))}
</div>

2

मुझे लगता है कि इस परिदृश्य को संभालने के लिए एक रेंडर प्रोप उपयुक्त तरीका है

आप पेरेंट को चाइल्ड कंपोनेंट में इस्तेमाल होने वाली आवश्यक प्रॉप्स प्रदान करते हैं, कुछ इस तरह से देखने के लिए पेरेंट कोड को रीक्रिएट करके:

const Parent = ({children}) => {
  const doSomething(value) => {}

  return children({ doSomething })
}

फिर बच्चे के घटक में आप माता-पिता द्वारा प्रदान किए गए फ़ंक्शन का इस तरह से उपयोग कर सकते हैं:

class Child extends React {

  onClick() => { this.props.doSomething }

  render() { 
    return (<div onClick={this.onClick}></div>);
  }

}

अब मंगेतर का रुख इस तरह दिखेगा:

<Parent>
  {(doSomething) =>
   (<Fragment>
     <Child value="1" doSomething={doSomething}>
     <Child value="2" doSomething={doSomething}>
    <Fragment />
   )}
</Parent>

2

विधि 1 - क्लोन बच्चे

const Parent = (props) => {
   const attributeToAddOrReplace= "Some Value"
   const childrenWithAdjustedProps = React.Children.map(props.children, child =>
      React.cloneElement(child, { attributeToAddOrReplace})
   );

   return <div>{childrenWithAdjustedProps }</div>
}

विधि 2 - रचना संदर्भ का उपयोग करें

प्रसंग आपको बीच में घटकों के माध्यम से एक प्रोप के रूप में स्पष्ट रूप से पारित किए बिना एक गहरे बाल घटक के लिए एक प्रस्ताव पारित करने की अनुमति देता है।

संदर्भ में कमियां हैं:

  1. डेटा नियमित रूप से प्रवाह नहीं करता है - सहारा के माध्यम से।
  2. संदर्भ का उपयोग करना उपभोक्ता और प्रदाता के बीच एक अनुबंध बनाता है। किसी घटक का पुन: उपयोग करने के लिए आवश्यक आवश्यकताओं को समझना और दोहराया जाना अधिक कठिन हो सकता है।

एक रचनात्मक संदर्भ का उपयोग करना

export const Context = createContext<any>(null);

export const ComposableContext = ({ children, ...otherProps }:{children:ReactNode, [x:string]:any}) => {
    const context = useContext(Context)
    return(
      <Context.Provider {...context} value={{...context, ...otherProps}}>{children}</Context.Provider>
    );
}

function App() {
  return (
      <Provider1>
            <Provider2> 
                <Displayer />
            </Provider2>
      </Provider1>
  );
}

const Provider1 =({children}:{children:ReactNode}) => (
    <ComposableContext greeting="Hello">{children}</ComposableContext>
)

const Provider2 =({children}:{children:ReactNode}) => (
    <ComposableContext name="world">{children}</ComposableContext>
)

const Displayer = () => {
  const context = useContext(Context);
  return <div>{context.greeting}, {context.name}</div>;
};

थोड़ी देर हो गई, लेकिन क्या आप नोटेशन की व्याख्या कर सकते हैं {children}:{children:ReactNode}?
कैमिल

@camille, यह एक टाइपस्क्रिप्ट चीज़ है। अब इसे देखते हुए, मैं सिर्फ जावास्क्रिप्ट के साथ उत्तर दूंगा, और यहां तक ​​कि अगर मैं टाइपस्क्रिप्ट लिखता हूं, तो मैं इसे अलग तरीके से करूंगा। भविष्य में इसे संपादित कर सकते हैं।
बेन कार्प

1
@camille, मूल रूप से इसका अर्थ है कि जिसकी कुंजी "children"है वह प्रकार की हैReactNode
बेन कार्प

1

ऐसा करने का सबसे पतला तरीका:

    {React.cloneElement(this.props.children, this.props)}

5
क्या यह इस.प्रॉप्सचाइल्ड्रेन की नकल नहीं करता। और वास्तव में बच्चे की नकल करना?
अरशब अग्रवाल

1

किसी भी एक बच्चे के तत्व के लिए ऐसा करना चाहिए।

{React.isValidElement(this.props.children)
                  ? React.cloneElement(this.props.children, {
                      ...prop_you_want_to_pass
                    })
                  : null}

0

क्या यह आप की आवश्यकता है?

var Parent = React.createClass({
  doSomething: function(value) {
  }
  render: function() {
    return  <div>
              <Child doSome={this.doSomething} />
            </div>
  }
})

var Child = React.createClass({
  onClick:function() {
    this.props.doSome(value); // doSomething is undefined
  },  
  render: function() {
    return  <div onClick={this.onClick}></div>
  }
})

4
नहीं, मैं कुछ विशेष सामग्री के लिए अपने आवरण की सामग्री को बाधित नहीं करना चाहता।
प्लस-

0

कुछ कारण React.children मेरे लिए काम नहीं कर रहा था। इसी से मेरा काम बना है।

मैं सिर्फ बच्चे के लिए एक क्लास जोड़ना चाहता था। एक प्रोप को बदलने के समान

 var newChildren = this.props.children.map((child) => {
 const className = "MenuTooltip-item " + child.props.className;
    return React.cloneElement(child, { className });
 });

 return <div>{newChildren}</div>;

यहाँ ट्रिक React.cloneElement है । आप किसी भी तरह से किसी भी प्रस्ताव को पारित कर सकते हैं


0

रेंडर प्रॉप्स इस समस्या के लिए सबसे सटीक दृष्टिकोण है। चाइल्ड कंपोनेंट को पेरेंट्स कंपोनेंट में पास करने के बजाय बच्चों को प्रॉपर बनाएं, पेरेंट को चाइल्ड कंपोनेंट को मैनुअली रेंडर करें। रेंडर प्रतिक्रिया में अंतर्निहित प्रॉप्स है, जो फ़ंक्शन पैरामीटर लेता है। इस फ़ंक्शन में आप मूल पैरामीटर को कस्टम पैरामीटर के साथ जो कुछ भी आप चाहते हैं उसे प्रस्तुत कर सकते हैं। मूल रूप से यह वही काम करता है जो बच्चे को सहारा देता है, लेकिन यह अधिक अनुकूलन योग्य है।

class Child extends React.Component {
  render() {
    return <div className="Child">
      Child
      <p onClick={this.props.doSomething}>Click me</p>
           {this.props.a}
    </div>;
  }
}

class Parent extends React.Component {
  doSomething(){
   alert("Parent talks"); 
  }

  render() {
    return <div className="Parent">
      Parent
      {this.props.render({
        anythingToPassChildren:1, 
        doSomething: this.doSomething})}
    </div>;
  }
}

class Application extends React.Component {
  render() {
    return <div>
      <Parent render={
          props => <Child {...props} />
        }/>
    </div>;
  }
}

कोडपेन पर उदाहरण


0

कार्यात्मक घटकों का उपयोग करते समय, आपको अक्सर TypeError: Cannot add property myNewProp, object is not extensibleनए गुणों को सेट करने का प्रयास करते समय त्रुटि मिलेगी props.children। प्रॉप्स को क्लोन करके और फिर नए प्रोप्स के साथ बच्चे को स्वयं क्लोन करके इसके चारों ओर एक काम है।

const MyParentComponent = (props) => {
  return (
    <div className='whatever'>
      {props.children.map((child) => {
        const newProps = { ...child.props }
        // set new props here on newProps
        newProps.myNewProp = 'something'
        const preparedChild = { ...child, props: newProps }
        return preparedChild
      })}
    </div>
  )
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.