React.js,在触发函数之前等待setState完成?

时间:2016-05-23 22:35:12

标签: javascript reactjs state

这是我的情况:

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

6 个答案:

答案 0 :(得分:189)

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

请注意,findRoutes的呼叫现在位于setState()来电中, 作为第二个参数。
没有(),因为你正在传递函数。

答案 1 :(得分:10)

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

这可能会有所帮助

答案 2 :(得分:7)

根据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
}

答案 3 :(得分:2)

setState采用新状态和可选的回调函数,状态更新后将调用该函数。

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

答案 4 :(得分:2)

如果有人在这里登陆并使用钩子遇到相同的情况,可以通过以下过程归档相同的行为

const [data, setData] = useState(false);

useEffect(() => {
    doSomething(); // This is be executed when the state changes
}, [data]);

setdata(true);

这里的 useEffect 将在数据发生任何变化后运行,我们可以执行任何依赖任务。

答案 5 :(得分:0)

为什么还没有一个答案? setState()setState()触发的render()在您调用componentDidMount()(第一次执行render())和/或{{3} }(执行render()之后的任何时间)。 (链接到ReactJS.org文档。)

示例componentDidUpdate()

呼叫者,设置参考并设置状态...

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

呈现父级...

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

示例componentDidMount()

呼叫者,设置参考并设置状态...

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

呈现父级...

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

父母给孩子交还后,请参见componentDidUpdate()中的状态。

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