क्या मैं सेटस्टैट को अपडेट करने के बाद किसी फ़ंक्शन को निष्पादित कर सकता हूं?


174

मैं जेएससी रिएक्ट करने के लिए बहुत नया हूं (जैसा कि अभी शुरू हुआ है)। मुझे समझ नहीं आया कि कैसे काम करता है। मैं उपयोगकर्ता इनपुट के आधार पर एक ग्रिड बनाने के लिए रिएक्ट और ईज़ेल जेएस का संयोजन कर रहा हूं। यहाँ मेरा JS बिन है: http://jsbin.com/zatula/edit?js,output

यहाँ कोड है:

        var stage;

    var Grid = React.createClass({
        getInitialState: function() {
            return {
                rows: 10,
                cols: 10
            }
        },
        componentDidMount: function () {
            this.drawGrid();
        },
        drawGrid: function() {
            stage = new createjs.Stage("canvas");
            var rectangles = [];
            var rectangle;
            //Rows
            for (var x = 0; x < this.state.rows; x++)
            {
                // Columns
                for (var y = 0; y < this.state.cols; y++)
                {
                    var color = "Green";
                    rectangle = new createjs.Shape();
                    rectangle.graphics.beginFill(color);
                    rectangle.graphics.drawRect(0, 0, 32, 44);
                    rectangle.x = x * 33;
                    rectangle.y = y * 45;

                    stage.addChild(rectangle);

                    var id = rectangle.x + "_" + rectangle.y;
                    rectangles[id] = rectangle;
                }
            }
            stage.update();
        },
        updateNumRows: function(event) {
            this.setState({ rows: event.target.value });
            this.drawGrid();
        },
        updateNumCols: function(event) {
            this.setState({ cols: event.target.value });
            this.drawGrid();
        },
        render: function() {
            return (
                <div>
                    <div className="canvas-wrapper">
                        <canvas id="canvas" width="400" height="500"></canvas>
                        <p>Rows: { this.state.rows }</p>
                        <p>Columns: {this.state.cols }</p>
                    </div>
                    <div className="array-form">
                        <form>
                            <label>Number of Rows</label>
                            <select id="numRows" value={this.state.rows} onChange={ this.updateNumRows }>
                                <option value="1">1</option>
                                <option value="2">2</option>
                                <option value ="5">5</option>
                                <option value="10">10</option>
                                <option value="12">12</option>
                                <option value="15">15</option>
                                <option value="20">20</option>
                            </select>
                            <label>Number of Columns</label>
                            <select id="numCols" value={this.state.cols} onChange={ this.updateNumCols }>
                                <option value="1">1</option>
                                <option value="2">2</option>
                                <option value="5">5</option>
                                <option value="10">10</option>
                                <option value="12">12</option>
                                <option value="15">15</option>
                                <option value="20">20</option>
                            </select>
                        </form>
                    </div>    
                </div>
            );
        }
    });
    ReactDOM.render(
        <Grid />,
        document.getElementById("container")
    );

आप JS बिन में देख सकते हैं जब आप एक ड्रॉपडाउन के साथ पंक्तियों या स्तंभों की संख्या बदलते हैं, तो पहली बार कुछ भी नहीं होगा। अगली बार जब आप एक ड्रॉपडाउन मान बदलते हैं, तो ग्रिड पिछले राज्य की पंक्ति और स्तंभ मानों पर आ जाएगा। मैं अनुमान लगा रहा हूं कि यह इसलिए हो रहा है क्योंकि setState पूरा होने से पहले मेरा this.drawGrid () फ़ंक्शन निष्पादित हो रहा है। शायद कोई और कारण है?

आपके समय एवं मदद के लिए धन्यवाद!

जवाबों:


449

setState(updater[, callback]) एक async फ़ंक्शन है:

https://facebook.github.io/react/docs/react-component.html#setstate

आप एक समारोह को अंजाम दे सकते हैं जब सेटस्टैट दूसरे परम का उपयोग करके खत्म कर रहा हो callbackजैसे:

this.setState({
    someState: obj
}, () => {
    this.afterSetStateFinished();
});

32
या बस इस। स्ट्रेट ({someState: obj}, इस। आफ्टरसेट फ़िनिश);
अलेक्सी प्रोकोपोव

मैं जोड़ने के लिए है कि मेरे विशिष्ट उदाहरण में, मैं शायद कॉल करना चाहते हैं चाहते हैं this.drawGrid()में componentDidUpdateजैसे @kennedyyu सुझाव दिया है, क्योंकि किसी भी समय setStateसमाप्त हो गया है, मैं ग्रिड पुनः बनाने का (ताकि इस कोड की कुछ पंक्तियाँ की बचत होगी) चाहते हैं, लेकिन इसी कार्य को पूरा ।
मोनालिसा

शानदार जवाब ... मुझे बहुत मदद मिली
Mo HammaDD ReZa DehGhani

यह मेरे लिए बहुत समय बचाता है। धन्यवाद।
नयन दिन

28

rendersetStateयदि परिवर्तन हो तो घटक को फिर से प्रस्तुत करने के लिए हर बार बुलाया जाएगा । अगर आप अपने कॉल को drawGridअपने update*तरीकों से कॉल करने के बजाय वहां ले जाते हैं , तो आपको कोई समस्या नहीं होनी चाहिए।

यदि वह आपके लिए काम नहीं करता है, तो एक ओवरलोड भी है जो setStateदूसरे पैरामीटर के रूप में कॉलबैक लेता है। आपको अंतिम उपाय के रूप में इसका लाभ उठाने में सक्षम होना चाहिए।


2
धन्यवाद - आपका पहला सुझाव काम करता है और (ज्यादातर) समझ में आता है। मैंने ऐसा किया: render: function() { this.drawGrid(); return......
मोनालिसा Jan१

3
अहम, कृपया ऐसा न करें render()... sytolk के जवाब को स्वीकार किया जाना चाहिए
mfeineis

यह एक गलत उत्तर है, सेटस्ट्रेट इन्फेंटी लूप के लिए जाएगा और पेज को क्रैश कर देगा।
मेवरिक

जस्टिन, मुझे इस बात में दिलचस्पी है कि कॉलबैक को setStateअंतिम उपाय के रूप में क्यों इस्तेमाल किया जाना चाहिए। मैं यहां ज्यादातर लोगों से सहमत हूं कि यह उस दृष्टिकोण का उपयोग करने के लिए समझ में आता है।
मोनालिसा

1
@ यह हर रेंडर कॉल पर निष्पादित करने के लिए महंगा तरीका है, जबकि यह स्पष्ट रूप से हर कॉल पर आवश्यक नहीं है। यदि यह शुद्ध था तो reactअधिकांश मामलों में बहुत अधिक काम न करने का ध्यान रखना होगा, यह एक और पुस्तकालय है जिसे आप कम से कम करना चाहते हैं
mfeineis

14

बनाना setStateवापसी एकPromise

एक गुजर के अलावा callbackकरने के लिए setState()विधि, आप इसे एक लपेट कर सकते हैं asyncसमारोह और प्रयोग then()विधि - जो कुछ मामलों में एक क्लीनर कोड का उत्पादन हो सकता है:

(async () => new Promise(resolve => this.setState({dummy: true}), resolve)()
    .then(() => { console.log('state:', this.state) });

और यहाँ आप इसे एक और कदम आगे ले जा सकते हैं और एक पुन: प्रयोज्य setStateकार्य कर सकते हैं जो मेरी राय में उपरोक्त संस्करण से बेहतर है:

const promiseState = async state =>
    new Promise(resolve => this.setState(state, resolve));

promiseState({...})
    .then(() => promiseState({...})
    .then(() => {
        ...  // other code
        return promiseState({...});
    })
    .then(() => {...});

यह रिएक्ट 16.4 में ठीक काम करता है , लेकिन मैंने अभी तक रिएक्ट के पुराने संस्करणों में इसका परीक्षण नहीं किया है ।

यह भी ध्यान देने योग्य है कि आपके कॉलबैक कोड को componentDidUpdateविधि में रखना एक बेहतर अभ्यास है - शायद सभी मामलों में।


11

जब नए प्रॉप्स या स्टेट्स प्राप्त हो रहे हों (जैसे आप setStateयहां कॉल करते हैं), रिएक्ट कुछ फंक्शन्स को इनवाइट करेगा, जिन्हें कॉल किया जाता है componentWillUpdateऔरcomponentDidUpdate

अपने मामले में, बस componentDidUpdateकॉल करने के लिए एक फ़ंक्शन जोड़ेंthis.drawGrid()

यहाँ जे एस बिन में काम कर रहा है कोड

जैसा कि मैंने उल्लेख किया है, कोड में, के componentDidUpdateबाद लागू किया जाएगाthis.setState(...)

तो componentDidUpdateअंदर कॉल करने के लिए जा रहा हैthis.drawGrid()

घटक के बारे में और अधिक पढ़ जीवनचक्र प्रतिक्रिया में https://facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate


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