React.js, bir işlevi tetiklemeden önce setState'in bitmesini bekleyin.


108

Durumum şu:

  • this.handleFormSubmit () üzerinde this.setState () 'i çalıştırıyorum
  • this.handleFormSubmit () içinde this.findRoutes () çağırıyorum; - bu, this.setState () işleminin başarıyla tamamlanmasına bağlıdır
  • this.setState (); this.findRoutes çağrılmadan önce tamamlanmaz ...
  • This.findRoutes () 'i çağırmadan önce this.handleFormSubmit () içindeki this.setState ()' in bitmesini nasıl beklerim?

Subpar bir çözüm:

  • this.findRoutes () öğesini componentDidUpdate () içine koymak
  • bu kabul edilemez çünkü findRoutes () işleviyle ilgisi olmayan daha fazla durum değişikliği olacaktır. İlgisiz durum güncellendiğinde findRoutes () işlevini tetiklemek istemiyorum.

Lütfen aşağıdaki kod parçasına bakın:

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

Yanıtlar:


251

setState()bunun için kullanabileceğiniz isteğe bağlı bir geri arama parametresine sahiptir. Bunun için kodunuzu yalnızca biraz değiştirmeniz gerekir:

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

Çağrının findRoutesartık setState()ikinci parametre olarak çağrının içinde olduğuna dikkat edin . Fonksiyonu geçtiğiniz için
olmadan ().


2
İnanılmaz! Çok teşekkürler
malexanders

Bu, ReactNative'de setState'den sonra AnimatedValue'u sıfırlamak için güzel bir şekilde çalışacaktır.
SacWebDeveloper

Harika ~ Çok teşekkürler
吳 強 福

2
Genel bir sürümthis.setState({ name: "myname" }, function() { console.log("setState completed", this.state) })
Sasi Varunan

SetState'e birden fazla geri aramayı iletebilecek gibi görünmüyor. Geri aramaları zincirlemenin dağınık olmayan bir yolu var mı? Diyelim ki, hepsinin çalışması gereken 3 yöntemim ve tüm güncelleme durumu var. Bunu halletmenin tercih edilen yolu nedir?
Sean

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

bu yardımcı olabilir


10

setState()Yeni devletin belgelerine göre geri arama işlevine yansıtılmayabilir findRoutes(). İşte React belgelerinden alıntı :

setState (), this.state'i hemen değiştirmez, ancak bir bekleyen durum geçişi oluşturur. Bu yöntemi çağırdıktan sonra this.state'e erişmek potansiyel olarak mevcut değeri döndürebilir.

SetState çağrılarının eşzamanlı olarak çalışacağına dair bir garanti yoktur ve çağrılar performans kazanımları için toplu olarak işlenebilir.

İşte yapman gerektiğini önerdiğim şey. inputGeri arama işlevinde yeni durumları iletmelisiniz 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
}

findRoutes()İşlevi aşağıdaki gibi tanımlanmalıdır:

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
}

bunun ciddi bir kusuru var - setState()yeni duruma gerçek bir itiraz iletmek iyi değil çünkü yarış koşullarına yol açıyor
tar

İşte react belgelerinden başka bir alıntı (cevabınızı gönderdikten sonra güncellenmiş olabilir): "... componentDidUpdate veya setState geri çağırma (setState (güncelleyici, geri arama)) kullanın, her ikisinin de güncelleme yapıldıktan sonra tetiklenmesi garanti edilir. uygulandı ". Bu bana, yeni durumun kesinlikle geri arama işlevine yansıtıldığını söylüyor.
Andy

1

setState durum güncellendikten sonra çağrılan yeni durumu ve isteğe bağlı geri arama işlevini alır.

this.setState(
  {newState: 'whatever'},
  () => {/*do something after the state has been updated*/}
)

0

Neden bir cevap daha yok? setState()ve setState()-triggered render(), aradığınızda componentDidMount()(ilk kez render()çalıştırıldığında) ve / veya componentDidUpdate()( render()çalıştırıldıktan sonra herhangi bir zamanda ) yürütmeyi tamamladı . (Bağlantılar ReactJS.org belgelerine yöneliktir.)

Örnek componentDidUpdate()

Arayan, referans ayarla ve durumu ayarla ...

<Cmp ref={(inst) => {this.parent=inst}}>;
this.parent.setState({'data':'hello!'});

Ebeveyni işle ...

componentDidMount() {           // componentDidMount() gets called after first state set
    console.log(this.state.data);   // output: "hello!"
}
componentDidUpdate() {          // componentDidUpdate() gets called after all other states set
    console.log(this.state.data);   // output: "hello!"
}

Örnek componentDidMount()

Arayan, referans ayarla ve durumu ayarla ...

<Cmp ref={(inst) => {this.parent=inst}}>
this.parent.setState({'data':'hello!'});

Ebeveyni işle ...

render() {              // render() gets called anytime setState() is called
    return (
        <ChildComponent
            state={this.state}
        />
    );
}

Ebeveyn, çocuğu yeniden gönderdikten sonra, içindeki durumu görün componentDidUpdate().

componentDidMount() {           // componentDidMount() gets called anytime setState()/render() finish
console.log(this.props.state.data); // output: "hello!"
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.