web-dev-qa-db-fra.com

Puis-je exécuter une fonction après la mise à jour de setState?

Je suis très nouveau en React JS (comme dans, vient de commencer aujourd'hui). Je ne comprends pas très bien comment setState fonctionne. Je combine React et Easel JS pour dessiner une grille basée sur les entrées de l'utilisateur. Voici mon bin JS: http://jsbin.com/zatula/edit?js,output

Voici le code:

        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")
    );

Vous pouvez voir dans la corbeille JS que lorsque vous modifiez le nombre de lignes ou de colonnes à l'aide de l'une des listes déroulantes, rien ne se produit la première fois. La prochaine fois que vous modifierez une valeur de liste déroulante, la grille affichera les valeurs de ligne et de colonne de l'état précédent. Je suppose que cela se produit car ma fonction this.drawGrid () s’exécute avant la fin de setState. Peut-être il y a une autre raison?

Merci pour votre temps et votre aide!

126
monalisa717

setState(updater[, callback]) est une fonction asynchrone:

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

Vous pouvez exécuter une fonction après la fin de setState en utilisant le deuxième paramètre callback comme:

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

render sera appelé à chaque fois que vous setState restituera le composant s'il y a des modifications. Si vous déplacez votre appel vers drawGrid plutôt que de l'appeler dans vos méthodes update*, vous ne devriez pas avoir de problème.

Si cela ne fonctionne pas pour vous, il existe également une surcharge de setState qui prend un rappel en tant que second paramètre. Vous devriez pouvoir en profiter en dernier recours.

28
Justin Niessner

Faire setState retourne un Promise

En plus de passer d'une méthode callback à setState(), vous pouvez l'enrouler autour d'une fonction async et utiliser la méthode then(), qui peut parfois produire un code plus propre. :

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

Et ici, vous pouvez faire un pas de plus et créer une fonction réutilisable setState qui, à mon avis, est meilleure que la version ci-dessus:

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

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

Cela fonctionne très bien dans React 16.4, mais je ne l’ai pas encore testé dans les versions précédentes de React.

Il convient également de mentionner que le maintien de votre méthode rappel dans componentDidUpdate est une meilleure pratique dans la plupart des cas, probablement dans tous les cas.

10
Mahdi

quand de nouveaux accessoires ou états sont reçus (comme vous appelez setState ici), React invoquera certaines fonctions, appelées componentWillUpdate et componentDidUpdate

dans votre cas, ajoutez simplement une fonction componentDidUpdate à appeler this.drawGrid()

voici le code de travail dans JS Bin

comme je l'ai mentionné dans le code, componentDidUpdate sera invoqué après this.setState(...)

alors componentDidUpdate à l'intérieur va appeler this.drawGrid()

en savoir plus sur le composant Cycle de vie dans React https://facebook.github.io/react/docs/component -specs.html # update-composantwillupdate

10
Kennedy Yu