Tôi có thể thực thi một chức năng sau khi setState cập nhật xong không?


174

Tôi rất mới với React JS (như trong, mới bắt đầu hôm nay). Tôi hoàn toàn không hiểu cách setState hoạt động. Tôi đang kết hợp React và Easel JS để vẽ lưới dựa trên đầu vào của người dùng. Đây là thùng JS của tôi: http://jsbin.com/zatula/edit?js,output

Đây là mã:

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

Bạn có thể thấy trong thùng JS khi bạn thay đổi số lượng hàng hoặc cột bằng một trong những lần thả xuống, sẽ không có gì xảy ra lần đầu tiên. Lần tới khi bạn thay đổi giá trị thả xuống, lưới sẽ rút về các giá trị hàng và cột của trạng thái trước đó. Tôi đoán điều này đang xảy ra vì hàm this.drawGrid () của tôi đang thực thi trước khi setState hoàn tất. Có lẽ có một lý do khác?

Xin cám ơn về thời gian và sự giúp đỡ của bạn!

Câu trả lời:


448

setState(updater[, callback]) là một hàm async:

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

Bạn có thể thực thi một chức năng sau khi setState kết thúc bằng tham số thứ hai callbacknhư:

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

32
hoặc chỉ this.setState ({someState: obj}, this.afterSetStateFinished);
Aleksei Prokopov

Tôi muốn thêm rằng trong ví dụ cụ thể của tôi, tôi có lẽ muốn gọi this.drawGrid()trong componentDidUpdatenhư @kennedyyu đề nghị, vì bất cứ lúc nào setStatekết thúc, tôi sẽ muốn vẽ lại lưới điện (vì vậy đây sẽ tiết kiệm một số dòng mã), nhưng thực hiện được điều tương tự .
monalisa717

Câu trả lời tuyệt vời ... đã giúp tôi rất nhiều
Mo HammaD ReZa DehGhani

Nó tiết kiệm rất nhiều thời gian cho tôi. Cảm ơn.
Naya Dey

28

rendersẽ được gọi mỗi khi bạn setStatekết xuất lại thành phần nếu có thay đổi. Nếu bạn chuyển cuộc gọi của mình đến drawGridđó thay vì gọi nó theo update*phương thức của mình , bạn sẽ không gặp vấn đề gì.

Nếu điều đó không phù hợp với bạn, thì cũng có một tình trạng quá tải setStatesẽ gọi lại làm tham số thứ hai. Bạn sẽ có thể tận dụng điều đó như là phương sách cuối cùng.


2
Cảm ơn bạn - đề xuất đầu tiên của bạn hoạt động và (chủ yếu) có ý nghĩa. Tôi đã làm điều này: render: function() { this.drawGrid(); return......
monalisa717

3
Ahem, xin đừng làm điều này trong render()... câu trả lời của sytolk nên là câu trả lời được chấp nhận
mfeineis

Đây là một câu trả lời sai, setState sẽ đi vào vòng lặp infintie và sẽ làm sập trang.
Maverick

Justin, tôi quan tâm đến lý do tại sao nói rằng cuộc gọi lại setStatenên được sử dụng là biện pháp cuối cùng. Tôi đồng ý với hầu hết mọi người ở đây rằng sử dụng phương pháp đó là hợp lý.
monalisa717

1
@Rohmer đây là cách tốn kém để thực hiện trên mỗi cuộc gọi kết xuất trong khi rõ ràng nó không cần thiết cho mỗi cuộc gọi. Nếu đó là thuần túy reactthì vdom sẽ đảm bảo không làm quá nhiều công việc trong hầu hết các trường hợp, đây là sự kết hợp với một thư viện khác mà bạn muốn giảm thiểu
mfeineis

14

Trả setStatelại mộtPromise

Ngoài đi qua một callbackđến setState()phương pháp, bạn có thể quấn nó xung quanh một asyncchức năng và sử dụng các then()phương pháp - mà trong một số trường hợp có thể tạo ra một mã sạch hơn:

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

Và ở đây bạn có thể tiến lên một bước này và thực hiện một setStatechức năng có thể sử dụng lại mà theo tôi là tốt hơn phiên bản trên:

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

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

Điều này hoạt động tốt trong React 16.4, nhưng tôi chưa thử nghiệm nó trong các phiên bản React trước đó .

Cũng đáng đề cập rằng việc giữ mã gọi lại của bạn trong componentDidUpdatephương thức là một cách thực hành tốt hơn trong hầu hết - có lẽ là tất cả, các trường hợp.


11

khi các đạo cụ hoặc trạng thái mới được nhận (như bạn gọi setStateở đây), React sẽ gọi một số chức năng, được gọi componentWillUpdatecomponentDidUpdate

trong trường hợp của bạn, chỉ cần thêm một componentDidUpdatechức năng để gọithis.drawGrid()

Đây là mã làm việc trong JS Bin

như tôi đã đề cập, trong mã, componentDidUpdatesẽ được gọi sauthis.setState(...)

sau đó componentDidUpdatebên trong sẽ gọithis.drawGrid()

đọc thêm về Vòng đời thành phần trong React https://facebook.github.io/react/docs/component-specs.html#updating-componentwillupdate


thay vì chỉ dán liên kết. vui lòng thêm các phần có liên quan trong câu trả lời.
phượng hoàng
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.