React.js、関数をトリガーする前にsetStateが完了するのを待ちますか?


105

これが私の状況です:

  • this.handleFormSubmit()でthis.setState()を実行しています
  • this.handleFormSubmit()内で、this.findRoutes();を呼び出しています。-this.setState()の正常な完了に依存します
  • this.setState(); this.findRoutesが呼び出される前に完了しません...
  • this.findRoutes()を呼び出す前に、this.handleFormSubmit()内のthis.setState()が完了するのを待つにはどうすればよいですか?

準ソリューション:

  • this.findRoutes()をcomponentDidUpdate()に配置する
  • findRoutes()関数とは関係のない状態の変化が多くなるため、これは受け入れられません。無関係な状態が更新されたときにfindRoutes()関数をトリガーしたくありません。

以下のコードスニペットをご覧ください。

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

回答:


245

setState()これに使用できるオプションのコールバックパラメータがあります。コードを少し変更するだけで、次のようになります。

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

findRoutessetState()呼び出しが2番目のパラメーターとして呼び出しの内部にあることに注意してください。
なし()あなたが機能を渡しているので。


2
すごい!
どうも

これは、ReactNativeのsetStateの後にAnimatedValueをリセットするのに適しています。
SacWebDeveloper 2017

よろしく
お願いし

2
一般的なバージョンthis.setState({ name: "myname" }, function() { console.log("setState completed", this.state) })
Sasi Varunan

setStateに複数のコールバックを渡すことができるようには見えません。コールバックをチェーン化するための面倒な方法はありますか?すべてを実行する必要がある3つのメソッドと、すべての状態を更新するとします。これを処理するための好ましい方法は何ですか?
Sean

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

これは役に立つかもしれません


10

setState()新しい状態のドキュメントによると、コールバック関数に反映されない場合がありますfindRoutes()。これはReact docsからの抜粋です:

setState()はthis.stateをすぐには変更しませんが、保留中の状態遷移を作成します。このメソッドを呼び出した後でthis.stateにアクセスすると、既存の値が返される可能性があります。

setStateの呼び出しの同期操作の保証はなく、パフォーマンスを向上させるために呼び出しをバッチ処理することができます。

だからここに私があなたがすべきことを提案します。inputコールバック関数で新しい状態を渡す必要があります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()機能は次のように定義する必要があります。

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
}

これには重大な欠陥がsetState()あります。新しい状態としてリテラルobjを渡すことは、競合状態につながるため、良くありません
tar

これは、反応ドキュメントからの別の引用です(回答を投稿してから更新されている可能性があります): "... use componentDidUpdateまたはsetStateコールバック(setState(updater、callback)))適用されました。」これは、新しい状態が最も確実にコールバック関数に反映されることを私に言います。
アンディ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.