Reactjs: माता-पिता से गतिशील बाल घटक राज्य या सहारा को कैसे संशोधित किया जाए?


90

मैं अनिवार्य रूप से प्रतिक्रिया में टैब बनाने की कोशिश कर रहा हूं, लेकिन कुछ मुद्दों के साथ।

यहाँ फ़ाइल है page.jsx

<RadioGroup>
    <Button title="A" />
    <Button title="B" />
</RadioGroup>

जब आप बटन A पर क्लिक करते हैं, तो RadioGroup घटक को बटन B का चयन करना होता है

"चयनित" का अर्थ केवल एक राज्य या संपत्ति से एक वर्गनाम है

यहाँ है RadioGroup.jsx:

module.exports = React.createClass({

    onChange: function( e ) {
        // How to modify children properties here???
    },

    render: function() {
        return (<div onChange={this.onChange}>
            {this.props.children}
        </div>);
    }

});

स्रोत Button.jsxवास्तव में मायने नहीं रखता है, इसमें एक नियमित HTML रेडियो बटन है जो मूल डोम onChangeइवेंट को ट्रिगर करता है

अपेक्षित प्रवाह है:

  • बटन "ए" पर क्लिक करें
  • बटन "ए" ऑनग्रो, देशी डोम इवेंट को चलाता है, जो रेडियोग्रुप तक बुलबुले रखता है
  • RadioGroup onChange श्रोता को कहा जाता है
  • RadioGroup को बटन B को डी-सेलेक्ट करना होगा । यह मेरा सवाल है।

यहाँ मुख्य समस्या यह है कि मैं का सामना कर रहा हूँ है: मैं नहीं ले जा सकते <Button>में रोंRadioGroup , क्योंकि इस की संरचना ऐसी है कि बच्चे हैं मनमाने ढंग से । यानी मार्कअप हो सकता है

<RadioGroup>
    <Button title="A" />
    <Button title="B" />
</RadioGroup>

या

<RadioGroup>
    <OtherThing title="A" />
    <OtherThing title="B" />
</RadioGroup>

मैंने कुछ चीजें आजमाई हैं।

प्रयास करें: में RadioGroupकी onChange हैंडलर:

React.Children.forEach( this.props.children, function( child ) {

    // Set the selected state of each child to be if the underlying <input>
    // value matches the child's value

    child.setState({ selected: child.props.value === e.target.value });

});

मुसीबत:

Invalid access to component property "setState" on exports at the top
level. See react-warning-descriptors . Use a static method
instead: <exports />.type.setState(...)

प्रयास करें: में RadioGroupकी onChange हैंडलर:

React.Children.forEach( this.props.children, function( child ) {

    child.props.selected = child.props.value === e.target.value;

});

समस्या: कुछ नहीं होता है, यहां तक ​​कि मैं Buttonकक्षा को एक componentWillReceivePropsविधि देता हूं


प्रयास: मैंने बच्चों के लिए माता-पिता की कुछ विशिष्ट स्थिति को पारित करने का प्रयास किया, इसलिए मैं सिर्फ माता-पिता की स्थिति को अपडेट कर सकता हूं और बच्चों को स्वचालित रूप से जवाब देना होगा। RadioGroup के रेंडर फ़ंक्शन में:

React.Children.forEach( this.props.children, function( item ) {
    this.transferPropsTo( item );
}, this);

मुसीबत:

Failed to make request: Error: Invariant Violation: exports: You can't call
transferPropsTo() on a component that you don't own, exports. This usually
means you are calling transferPropsTo() on a component passed in as props
or children.

खराब समाधान # 1 : प्रतिक्रिया-addons.js cloneWithProps विधि का उपयोग करें बच्चों को क्लोन RadioGroupकरने के लिए उन्हें सौंपने में सक्षम होने के लिए समय देने के लिए विधि

बुरा समाधान # 2 : HTML / JSX के आसपास एक अमूर्त को लागू करें ताकि मैं गुणों में गतिशील रूप से पास कर सकूं (मुझे मार डालो):

<RadioGroup items=[
    { type: Button, title: 'A' },
    { type: Button, title: 'B' }
]; />

और फिर RadioGroupगतिशील रूप से इन बटनों का निर्माण करें।

यह सवाल मेरी मदद नहीं करता है क्योंकि मुझे अपने बच्चों को यह जानने की आवश्यकता है कि वे क्या कर रहे हैं


यदि बच्चे मनमानी कर सकते हैं, तो RadioGroupसंभवतः यह कैसे जान सकता है कि उसे अपने मनमाने बच्चों की किसी घटना पर प्रतिक्रिया देने की आवश्यकता है? इसके बच्चों के बारे में कुछ जानना जरूरी है।
रॉस एलन

1
सामान्य तौर पर, यदि आप किसी ऐसे घटक के गुणों को संशोधित करना चाहते हैं जो आपके पास नहीं है, तो इसका उपयोग करके क्लोन करें React.addons.cloneWithPropsऔर जिस नए प्रॉप को आप चाहते हैं उसे पास करें। propsअपरिवर्तनीय हैं, इसलिए आप एक नया हैश बना रहे हैं, इसे वर्तमान प्रॉप्स के साथ विलय कर रहे हैं, और नए हैश को propsबाल घटक के नए उदाहरण के रूप में पास कर रहे हैं।
रॉस एलन

जवाबों:


42

मुझे यकीन नहीं है कि आप क्यों कहते हैं कि उपयोग cloneWithPropsकरना एक बुरा समाधान है, लेकिन यहां इसका उपयोग करना एक कार्यशील उदाहरण है।

var Hello = React.createClass({
    render: function() {
        return <div>Hello {this.props.name}</div>;
    }
});

var App = React.createClass({
    render: function() {
        return (
            <Group ref="buttonGroup">
                <Button key={1} name="Component A"/>
                <Button key={2} name="Component B"/>
                <Button key={3} name="Component C"/>
            </Group>
        );
    }
});

var Group = React.createClass({
    getInitialState: function() {
        return {
            selectedItem: null
        };
    },

    selectItem: function(item) {
        this.setState({
            selectedItem: item
        });
    },

    render: function() {
        var selectedKey = (this.state.selectedItem && this.state.selectedItem.props.key) || null;
        var children = this.props.children.map(function(item, i) {
            var isSelected = item.props.key === selectedKey;
            return React.addons.cloneWithProps(item, {
                isSelected: isSelected,
                selectItem: this.selectItem,
                key: item.props.key
            });
        }, this);

        return (
            <div>
                <strong>Selected:</strong> {this.state.selectedItem ? this.state.selectedItem.props.name : 'None'}
                <hr/>
                {children}
            </div>
        );
    }

});

var Button = React.createClass({
    handleClick: function() {
        this.props.selectItem(this);
    },

    render: function() {
        var selected = this.props.isSelected;
        return (
            <div
                onClick={this.handleClick}
                className={selected ? "selected" : ""}
            >
                {this.props.name} ({this.props.key}) {selected ? "<---" : ""}
            </div>
        );
    }

});


React.renderComponent(<App />, document.body);

यहाँ एक jsFiddle यह कार्रवाई में दिखा रहा है।

संपादित करें : यहाँ गतिशील टैब सामग्री के साथ एक और पूर्ण उदाहरण है: jsFiddle


15
नोट: cloneWithProps को हटा दिया गया है। इसके बजाय React.cloneElement का उपयोग करें।
चेन-त्सू लिन

8
यह कुछ करने के लिए अविश्वसनीय रूप से जटिल है डी 3 / जेक्वेरी सिर्फ एक के साथ कर सकता है: पर चयनकर्ता नहीं this। क्या रिएक्ट का उपयोग करने के अलावा कोई वास्तविक लाभ है?
उदाहरण के द्वारा सीखना आँकड़े

FYI करें .. यह "पैरेंट स्टेट से बच्चों की स्थिति को अपडेट नहीं कर रहा है", यह चाइल्ड स्टेट को अपडेट करने के लिए पेरेंट स्टेट को अपडेट करने वाला बच्चा है। यहाँ कबाड़ में अंतर है। मामले में यह लोगों को भ्रमित करता है।
स्कलाज १२'१६

1
@Incodeveritas आप सही हैं, भाई-बहन का रिश्ता, माता-पिता और बच्चा-बच्चा थोड़ा जटिल है। यह चीजों को करने का एक मॉड्यूलर तरीका है। लेकिन ध्यान रखें कि चीजों को प्राप्त करने के लिए JQuery एक त्वरित हैक है, ReactJS एक आर्केस्ट्रा के अनुसार चीजों को रखता है।
स्कलाज

18

बटन स्टेटलेस होना चाहिए। एक बटन के गुणों को स्पष्ट रूप से अपडेट करने के बजाय, केवल समूह की अपनी स्थिति को अपडेट करें और फिर से प्रस्तुत करें। समूह की रेंडर विधि को बटन को रेंडर करते समय उसकी स्थिति को देखना चाहिए और केवल सक्रिय बटन को "सक्रिय" (या कुछ) पास करना चाहिए।


विस्तार करने के लिए, बटन पर क्लिक करें या अन्य प्रासंगिक तरीकों को माता-पिता से सेट किया जाना चाहिए ताकि कोई भी क्रिया माता-पिता में वापस राज्य स्थापित करने के लिए कॉल करे, न कि बटन में ही। इस तरह से बटन केवल माता-पिता की वर्तमान स्थिति का एक स्टेटलेस प्रतिनिधित्व है।
डेविड मॉर्टेंसन

6

शायद मेरा एक अजीब समाधान है, लेकिन पर्यवेक्षक पैटर्न का उपयोग क्यों नहीं करते हैं?

RadioGroup.jsx

module.exports = React.createClass({
buttonSetters: [],
regSetter: function(v){
   buttonSetters.push(v);
},
handleChange: function(e) {
   // ...
   var name = e.target.name; //or name
   this.buttonSetters.forEach(function(v){
      if(v.name != name) v.setState(false);
   });
},
render: function() {
  return (
    <div>
      <Button title="A" regSetter={this.regSetter} onChange={handleChange}/>
      <Button title="B" regSetter={this.regSetter} onChange={handleChange} />
    </div>
  );
});

Button.jsx

module.exports = React.createClass({

    onChange: function( e ) {
        // How to modify children properties here???
    },
    componentDidMount: function() {
         this.props.regSetter({name:this.props.title,setState:this.setState});
    },
    onChange:function() {
         this.props.onChange();
    },
    render: function() {
        return (<div onChange={this.onChange}>
            <input element .../>
        </div>);
    }

});

शायद आपको कुछ और चाहिए, लेकिन मुझे यह बहुत शक्तिशाली लगा,

मैं वास्तव में एक बाहरी मॉडल का उपयोग करना पसंद करता हूं जो विभिन्न कार्यों के लिए पर्यवेक्षक रजिस्टर तरीके प्रदान करता है


क्या नोड के लिए यह बुरा रूप नहीं है कि किसी दूसरे नोड पर स्पष्ट रूप से सेटस्टेट कहा जाए? रेडियोग्रेग पर कुछ राज्य को अपडेट करने का एक और प्रतिक्रियात्मक तरीका होगा, एक और रेंडर पास को ट्रिगर करना जिसमें आप आवश्यक के रूप में वंश के प्रॉप को अपडेट कर सकते हैं?
21

1
स्पष्ट रूप से? नहीं, पर्यवेक्षक सिर्फ एक कॉलबैक कहते हैं, यह सेटस्टेट होना होता है, लेकिन वास्तव में मैं इसे निर्दिष्ट कर सकता था। ssetState.bind (यह) और इसलिए विशेष रूप से खुद को बाइंड करें। ठीक है, अगर मुझे ईमानदार होना था, तो मुझे एक स्थानीय फ़ंक्शन / पद्धति को परिभाषित करना चाहिए था जो सेटस्टैट को कॉल करता है और इसे प्रेक्षक में पंजीकृत करता है
Daniele Cruciani

1
क्या मैं यह गलत पढ़ रहा हूं, या क्या आपके पास एक वस्तु में एक ही नाम के दो क्षेत्र हैं Button.jsx?
जॉनके

Button.jsx शामिल है onChange()औरonChange(e)
जोश

पहले निकालें, यह प्रश्न (प्रथम प्रश्न) से कट और पेस्ट है। यह बात नहीं है, यह काम करने वाला कोड नहीं है, न ही यह होगा।
डेनियल क्रूसियन

0

एक ऐसी वस्तु बनाएं जो माता-पिता और बच्चे के बीच बिचौलिया का काम करे। इस ऑब्जेक्ट में माता-पिता और बच्चे दोनों में फ़ंक्शन संदर्भ शामिल हैं। ऑब्जेक्ट को तब माता-पिता से बच्चे के लिए एक प्रस्ताव के रूप में पारित किया जाता है। यहाँ कोड उदाहरण:

https://stackoverflow.com/a/61674406/753632

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