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

IT技术 javascript reactjs state
2021-03-23 16:32:10

这是我的情况:

  • 在 this.handleFormSubmit() 我正在执行 this.setState()
  • 在 this.handleFormSubmit() 中,我正在调用 this.findRoutes(); - 这取决于 this.setState() 的成功完成
  • this.setState(); 在此之前未完成。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个回答

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()调用内部,作为第二个参数。
没有()因为你正在传递函数。

看起来您不能将多个回调传递给 setState。有没有一种简单的链接回调的方法?假设我有 3 个方法都需要运行,并且所有更新状态。处理这个问题的首选方法是什么?
2021-06-03 16:32:10
如果没有更多信息,我认为 1 回调将是一个容器,它调用您的 3 个方法中的任何一个(如果需要按顺序触发它们)。或者容器按顺序调用您的 3 个方法,然后执行一个setState()(如果您真的不需要连续 4 个状态更改)。你能详细说明一下美国的具体情况吗?
2021-06-05 16:32:10
这对于在 ReactNative 中的 setState 之后重置 AnimatedValue 非常有用。
2021-06-11 16:32:10
一个通用版本 this.setState({ name: "myname" }, function() { console.log("setState completed", this.state) })
2021-06-14 16:32:10
为我工作......非常感谢。
2021-06-17 16:32:10
       this.setState(
        {
            originId: input.originId,
            destinationId: input.destinationId,
            radius: input.radius,
            search: input.search
        },
        function() { console.log("setState completed", this.state) }
       )

这可能会有所帮助

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

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

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

setdata(true);

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

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

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

根据setState()新状态的文档可能不会反映在回调函数中findRoutes()这是React 文档的摘录

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
}
这是来自 react 文档的另一个引用(自您发布答案后可能已更新):“...使用 componentDidUpdate 或 setState 回调 (setState(updater, callback)),其中任何一个都保证在更新后触发已应用”。这对我说,新状态绝对反映在回调函数中。
2021-06-13 16:32:10
这有一个严重的缺陷 - 将文字 obj 传递给setState()作为新状态并不好,因为它会导致竞争条件
2021-06-20 16:32:10