React.js, tunggu setState selesai sebelum memicu sebuah fungsi?

108

Inilah situasi saya:

  • pada this.handleFormSubmit () Saya menjalankan this.setState ()
  • di dalam this.handleFormSubmit (), saya memanggil this.findRoutes (); - yang bergantung pada keberhasilan penyelesaian this.setState ()
  • this.setState (); tidak selesai sebelum ini.findRoutes dipanggil ...
  • Bagaimana cara menunggu this.setState () di dalam this.handleFormSubmit () selesai sebelum memanggil this.findRoutes ()?

Solusi di bawah standar:

  • meletakkan this.findRoutes () di componentDidUpdate ()
  • ini tidak dapat diterima karena akan ada lebih banyak perubahan status yang tidak terkait dengan fungsi findRoutes (). Saya tidak ingin memicu fungsi findRoutes () saat status yang tidak terkait diperbarui.

Silakan lihat cuplikan kode di bawah ini:

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

Jawaban:

248

setState()memiliki parameter callback opsional yang dapat Anda gunakan untuk ini. Anda hanya perlu mengubah kode Anda sedikit, menjadi ini:

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

Perhatikan panggilan ke findRoutessekarang ada di dalam setState()panggilan, sebagai parameter kedua.
Tanpa ()karena Anda melewatkan fungsi tersebut.

wintvelt
sumber
2
Luar biasa! Terima kasih banyak
malexanders
Ini akan bekerja dengan baik untuk menyetel ulang AnimatedValue setelah setState di ReactNative.
SacWebDeveloper
Hebat ~ Terima kasih banyak
吳 強 福
2
Versi generikthis.setState({ name: "myname" }, function() { console.log("setState completed", this.state) })
Sasi Varunan
Sepertinya Anda tidak bisa meneruskan lebih dari satu callback ke setState. Apakah ada cara yang tidak berantakan untuk merangkai panggilan balik? Katakanlah saya punya 3 metode yang semuanya perlu dijalankan, dan semua status pembaruan. Apa cara yang disukai untuk menangani ini?
Sean
17
       this.setState(
        {
            originId: input.originId,
            destinationId: input.destinationId,
            radius: input.radius,
            search: input.search
        },
        function() { console.log("setState completed", this.state) }
       )

ini mungkin bisa membantu

Harshit Singhai
sumber
10

Menurut dokumen setState(), status baru mungkin tidak tercermin dalam fungsi callback findRoutes(). Berikut adalah ekstrak dari dokumen React :

setState () tidak langsung memutasi this.state tetapi membuat transisi status tertunda. Mengakses this.state setelah memanggil metode ini berpotensi mengembalikan nilai yang sudah ada.

Tidak ada jaminan operasi sinkron dari panggilan ke setState dan panggilan dapat dikelompokkan untuk mendapatkan performa.

Jadi, inilah yang saya usulkan yang harus Anda lakukan. Anda harus meneruskan status baru inputdalam fungsi callback 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
}

The findRoutes()fungsi harus didefinisikan seperti ini:

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
}
Pawan Samdani
sumber
ini memiliki kelemahan yang serius - mengajukan keberatan literal setState()sebagai negara bagian baru tidak baik karena mengarah ke kondisi ras
tar
berikut kutipan lain dari dokumen react (yang mungkin telah diperbarui sejak Anda memposting jawaban Anda): "... gunakan componentDidUpdate atau panggilan balik setState (setState (updater, callback)), salah satunya dijamin akan diaktifkan setelah pembaruan telah diterapkan ". Ini memberi tahu saya bahwa status baru paling pasti tercermin dalam fungsi callback.
Andy
0

Mengapa tidak satu jawaban lagi? setState()dan setState()-triggered render()telah menyelesaikan eksekusi saat Anda memanggil componentDidMount()(pertama kali render()dijalankan) dan / atau componentDidUpdate()(setiap saat setelah render()dijalankan). (Tautan ke dokumen ReactJS.org.)

Contoh dengan componentDidUpdate()

Penelepon, atur referensi, dan setel status ...

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

Jadikan induk ...

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!"
}

Contoh dengan componentDidMount()

Penelepon, atur referensi, dan setel status ...

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

Jadikan induk ...

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

Setelah orang tua merender anak, lihat status dalam componentDidUpdate().

componentDidMount() {           // componentDidMount() gets called anytime setState()/render() finish
console.log(this.props.state.data); // output: "hello!"
}
HoldOffHunger
sumber
0

setState mengambil status baru dan fungsi panggilan balik opsional yang dipanggil setelah status diperbarui.

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