React State 在回调函数执行前不会更新(版本 16.4.1)

huangapple go评论57阅读模式
英文:

React State not updating before callback function executes (Version 16.4.1)

问题

我有一个React的onChange方法,它在一个下拉框的用户界面组件上(自定义React组件,不是标准HTML)执行,当用户从下拉框中选择一个项目时,它会更新状态为新选择的值,然后进行回调以根据这个新状态从API中检索新数据。

尽管API调用位于回调中,但状态总是比实际交互滞后1次,这意味着如果我选择1,它将使用相关状态变量设置为0(默认值)进行API调用,如果我选择2,它将使用相关状态变量设置为1进行API调用。

通常情况下,这种情况发生是因为被调用的函数不是回调函数,但在这种情况下是回调函数,所以我困惑状态为什么保持滞后。

我知道没有其他函数触发,因为没有ComponentDidUpdate的调用或其他干扰此过程的东西。

我通过控制台日志确认,在设置状态之前,onChange函数中状态应该设置为的新值是正确的,但在回调函数中状态没有设置为新值。

我以前认为这是不可能的,对于如何排除此问题,我感到困惑,所以欢迎任何关于可能导致此问题的想法。

编辑:以下是代码(名称已泛化,一些细节已排除,如权限检查代码等)

当由于回调函数的调用而执行此代码时,apiFieldValue始终如上所述滞后,尽管它位于onChange函数的回调中。我无法分享更多信息,因为这是我没有权利分发的代码,因此无法提供更多信息。

onChangeFunction(newValue) {
    this.setState({ stateValue: newValue }, this.ApiCallback());
}

ApiCallback() {
    var canMakeCall = this.state.hasPermissions;
    var apiFieldValue = this.state.stateValue;

    if (canMakeCall) {
        let response = genericHttpClient.post("apiurl.com", { apiField: apiFieldValue, credentials: this.state.userCredentials });
        // ...
    }
}
英文:

I have a react onChange method on a dropdown UI component (Custom react component, not standard HTML) which updates the state to the newly selected value when a user selects an item from the dropdown, then makes a callback to retrieve new data from an API based on this new state.

Despite the API call being in a callback, the state is always stale by 1 interaction, meaning if I select 1, it will make the API call with the relevant state variable set to 0 (default value), and if I then select 2, it makes the API call with the relevant state variable set to 1.

Usually this happens because the function being called is NOT a callback, but in this case it is so I am confused how the state remains stale.

I know there are not other functions firing as there are no ComponentDidUpdate calls or anything else to interfere with this process.

I have confirmed with console logging that the new value that the state is supposed to be set to is correct in the onChange function prior to setting state, and yet the state is not set to the new value in the callback function.

I didn't think this was possible and am stumped on what to try next to troubleshoot this, so any ideas on what this might be caused by are appreciated.

Edit: Here is code (Names genericized, some details excluded such as permission checking code etc.)

When this code executes due to the callback function being called, apiFieldValue is always stale as described, despite being in the callback from the onChange function. I cannot share significantly more than that since it is code that I do not have rights to distribute and as such cannot supply.

onChangeFunction (newValue) 
{
    this.setState({ stateValue: newValue}, this.ApiCallback())
}

ApiCallback (){
   var canMakeCall = this.state.hasPermissions,
       apiFieldValue = this.state.stateValue

   if (canMakeCall){
    let response = genericHttpClient.post("apiurl.com", {apiField: apiFieldValue, credentials: this.state.userCredentials})
...
}

}

</details>


# 答案1
**得分**: 0

状态在进行API调用之前不会更新。只需在进行调用时,像下面示例中所示,将新值传递给API,而不是传递状态。

另一个选项是使用`useEffect()`钩子。听起来您正在使用基于类的组件,所以如果这使您感到困惑,请不要担心。我已经提供了两种选项的代码。

```javascript
// 通过将值传递给回调函数
onChangeFunction(newValue) {
  this.setState({
    stateValue: newValue
  });
  ApiCallback(newValue);
}

ApiCallback(value) {
  var canMakeCall = this.state.hasPermissions;
  var apiFieldValue = value;

  if (canMakeCall) {
    // ...
  }
}

// 使用 useEffect() 钩子
onChangeFunction(newValue) {
  this.setState(prevState => ({ ...prevState, valueKey: newValue }));
}

useEffect(() => {
  ApiCallback();
}, [state.valueKey]);

ApiCallback() {
  var canMakeCall = state.hasPermissions;
  var apiFieldValue = state.valueKey;

  if (canMakeCall) {
    // ...
  }
}

希望这能帮助您解决问题。

英文:

The state does not update before you make the api call. Simply pass in the newValue instead of the state as shown below when you make the call.

The other option is to use a useEffect() hook. It sounds like you are using class based components so don't worry about this if it is confusing. I've included the code for both options anyways.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

// By passing a value to the callback
onChangeFunction(newValue) {
  this.setState({
    stateValue: newValue
  })
  ApiCallback(newValue)
}

ApiCallback(value) {
  var canMakeCall = this.state.hasPermissions,
    apiFieldValue = value

  if (canMakeCall) {
    ...
  }
}


// With useEffect() hook
onChangeFunction(newValue) {
  this.setState(prev =&gt; {...prev, valueKey: newValue})
}

useEffect(() =&gt; {
  ApiCallback();
}, [state.valueKey])

ApiCallback() {
  var canMakeCall = state.hasPermissions,
    apiFieldValue = state.valueKey

  if (canMakeCall) {
    ...
  }
}

<!-- end snippet -->

答案2

得分: 0

这个陷阱,以及下面的注意事项。

简而言之,在调用this.ApiCallback()时,状态尚未更新。

有各种变通方法,但如果你想在this.setState上使用回调参数,你需要给它一个函数,这样它会在稍后被调用:

this.setState({ stateValue: newValue}, () => this.ApiCallback())
英文:

See this pitfall in the React docs, as well as the Caveats down below it.

In short, the state hasn't yet updated when you call your this.ApiCallback().

There are various workarounds, but if you want to use the callback parameter on this.setState, you would need to give it a function so it gets called later:

this.setState({ stateValue: newValue}, () =&gt; this.ApiCallback())

huangapple
  • 本文由 发表于 2023年4月7日 03:54:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75953289.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定