React.js, đợi setState kết thúc trước khi kích hoạt một hàm?


105

Đây là tình huống của tôi:

  • trên this.handleFormSubmit () Tôi đang thực thi this.setState ()
  • bên trong this.handleFormSubmit (), tôi đang gọi this.findRoutes (); - điều này phụ thuộc vào việc hoàn thành thành công this.setState ()
  • this.setState (); không hoàn thành trước this.findRoutes được gọi là ...
  • Làm cách nào để đợi this.setState () bên trong this.handleFormSubmit () kết thúc trước khi gọi this.findRoutes ()?

Một giải pháp phụ:

  • đặt this.findRoutes () trong componentDidUpdate ()
  • điều này không thể chấp nhận được vì sẽ có nhiều thay đổi trạng thái không liên quan đến hàm findRoutes (). Tôi không muốn kích hoạt hàm findRoutes () khi trạng thái không liên quan được cập nhật.

Vui lòng xem đoạn mã bên dưới:

handleFormSubmit: function(input){
                // Form Input
                this.setState({
                    originId: input.originId,
                    destinationId: input.destinationId,
                    radius: input.radius,
                    search: input.search
                })
                this.findRoutes();
            },
            handleMapRender: function(map){
                // Intialized Google Map
                directionsDisplay = new google.maps.DirectionsRenderer();
                directionsService = new google.maps.DirectionsService();
                this.setState({map: map});
                placesService = new google.maps.places.PlacesService(map);
                directionsDisplay.setMap(map);
            },
            findRoutes: function(){
                var me = this;
                if (!this.state.originId || !this.state.destinationId) {
                    alert("findRoutes!");
                    return;
                }
                var p1 = new Promise(function(resolve, reject) {
                    directionsService.route({
                        origin: {'placeId': me.state.originId},
                        destination: {'placeId': me.state.destinationId},
                        travelMode: me.state.travelMode
                    }, function(response, status){
                        if (status === google.maps.DirectionsStatus.OK) {
                            // me.response = response;
                            directionsDisplay.setDirections(response);
                            resolve(response);
                        } else {
                            window.alert('Directions config failed due to ' + status);
                        }
                    });
                });
                return p1
            },
            render: function() {
                return (
                    <div className="MapControl">
                        <h1>Search</h1>
                        <MapForm
                            onFormSubmit={this.handleFormSubmit}
                            map={this.state.map}/>
                        <GMap
                            setMapState={this.handleMapRender}
                            originId= {this.state.originId}
                            destinationId= {this.state.destinationId}
                            radius= {this.state.radius}
                            search= {this.state.search}/>
                    </div>
                );
            }
        });

Câu trả lời:


245

setState()có một tham số gọi lại tùy chọn mà bạn có thể sử dụng cho việc này. Bạn chỉ cần thay đổi mã của mình một chút, như sau:

// Form Input
this.setState(
  {
    originId: input.originId,
    destinationId: input.destinationId,
    radius: input.radius,
    search: input.search
  },
  this.findRoutes         // here is where you put the callback
);

Lưu ý rằng cuộc gọi đến findRouteshiện đang ở bên trong setState()cuộc gọi, là tham số thứ hai.
Mà không ()bởi vì bạn đang chuyển hàm.


2
Kinh ngạc! Cảm ơn rất nhiều
malexanders

Điều này sẽ hoạt động hiệu quả khi đặt lại AnimatedValue sau setState trong ReactNative.
SacWebDeveloper 14/02/17

Tuyệt vời ~ Cảm ơn rất nhiều
吳 強 福

2
Một phiên bản genericthis.setState({ name: "myname" }, function() { console.log("setState completed", this.state) })
Sasi Varunan

Có vẻ như bạn không thể chuyển nhiều hơn một lệnh gọi lại cho setState. Có cách nào để xâu chuỗi các lệnh gọi lại không lộn xộn không? Hãy nói rằng tôi có 3 phương thức cần phải chạy và tất cả trạng thái cập nhật. Cách ưa thích để xử lý điều này là gì?
Sean

17
       this.setState(
        {
            originId: input.originId,
            destinationId: input.destinationId,
            radius: input.radius,
            search: input.search
        },
        function() { console.log("setState completed", this.state) }
       )

điều này có thể hữu ích


10

Theo tài liệu của setState()trạng thái mới có thể không được phản ánh trong chức năng gọi lại findRoutes(). Đây là phần trích xuất từ tài liệu React :

setState () không đột biến this.state ngay lập tức nhưng tạo ra một chuyển đổi trạng thái đang chờ xử lý. Việc truy cập this.state sau khi gọi phương thức này có thể trả về giá trị hiện có.

Không có gì đảm bảo hoạt động đồng bộ của các cuộc gọi đến setState và các cuộc gọi có thể được thực hiện theo đợt để tăng hiệu suất.

Vì vậy, đây là những gì tôi đề xuất bạn nên làm. Bạn nên chuyển các trạng thái mới inputtrong hàm gọi lại findRoutes().

handleFormSubmit: function(input){
    // Form Input
    this.setState({
        originId: input.originId,
        destinationId: input.destinationId,
        radius: input.radius,
        search: input.search
    });
    this.findRoutes(input);    // Pass the input here
}

Các findRoutes()chức năng nên được định nghĩa như thế này:

findRoutes: function(me = this.state) {    // This will accept the input if passed otherwise use this.state
    if (!me.originId || !me.destinationId) {
        alert("findRoutes!");
        return;
    }
    var p1 = new Promise(function(resolve, reject) {
        directionsService.route({
            origin: {'placeId': me.originId},
            destination: {'placeId': me.destinationId},
            travelMode: me.travelMode
        }, function(response, status){
            if (status === google.maps.DirectionsStatus.OK) {
                // me.response = response;
                directionsDisplay.setDirections(response);
                resolve(response);
            } else {
                window.alert('Directions config failed due to ' + status);
            }
        });
    });
    return p1
}

này có một lỗ hổng nghiêm trọng - đi qua một obj đen để setState()như tình trạng mới không phải là tốt vì nó dẫn đến điều kiện chủng tộc
tar

đây là một trích dẫn khác từ tài liệu phản ứng (có thể đã được cập nhật kể từ khi bạn đăng câu trả lời của mình): "... sử dụng componentDidUpdate hoặc lệnh gọi lại setState (setState (cập nhật, gọi lại)), một trong số chúng được đảm bảo kích hoạt sau khi cập nhật đã được áp dụng ”. Điều này nói với tôi rằng trạng thái mới chắc chắn nhất được phản ánh trong hàm gọi lại.
Andy
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.