在Reactjs中是否存在setState()的同步替代

shu*_*wal 35 javascript reactjs

根据文档中的解释:

setState()不会立即改变this.state,但会创建挂起状态转换.调用此方法后访问this.state可能会返回现有值.

无法保证对setState的调用进行同步操作,并且可以对调用进行批处理以获得性能提升.

因此,由于setState()是同步的,并且无法保证其同步性能.是否存在setState()同步的替代方案.

例如

//initial value of cnt:0
this.setState({cnt:this.state.cnt+1})
alert(this.state.cnt);    //alert value:0
Run Code Online (Sandbox Code Playgroud)

由于该alert值是先前的值,因此可以alert value:1使用的替代方法是什么setState().

Stackoverflow上几乎没有问题类似于这个问题,但没有我能找到正确答案的地方.

Osc*_*nco 59

正如您从文档中读到的那样,没有同步替代方案,所描述的原因是性能提升.

但是我假设您想在更改状态后执行操作,可以通过以下方式实现:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
     x: 1
    };
    
    console.log('initial state', this.state);
  }
  
  updateState = () => {
   console.log('changing state');
    this.setState({
      x: 2
    },() => { console.log('new state', this.state); })
  }
  
  render() {
    return (
      <div>
      <button onClick={this.updateState}>Change state</button>
    </div>
    );
   
  }
}

ReactDOM.render(
  <MyComponent />,
  document.getElementById("react")
);
Run Code Online (Sandbox Code Playgroud)
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Run Code Online (Sandbox Code Playgroud)

  • 它不再工作并抛出如下错误: **警告:来自 useState() 和 useReducer() Hook 的状态更新不支持第二个回调参数。要在渲染后执行副作用,请在组件主体中使用 useEffect() 声明它。** (3认同)
  • @simaghoreyshi 仔细阅读问题和答案,这并不意味着与钩子一起使用,这是针对旧类组件的 (2认同)

S.K*_*ers 6

如果这是必需的,我建议在您的 setState 函数中使用回调(并且我还建议使用功能性 setState)。

状态更新后将调用回调。

例如,你的例子是

//initial value of cnt:0
this.setState(
    (state) => ({cnt: state.cnt+1}),
    () => { alert(this.state.cnt)}
)
Run Code Online (Sandbox Code Playgroud)

根据此处的文档:https : //facebook.github.io/react/docs/react-component.html#setstate

注意:官方文档说,“通常我们建议使用 componentDidUpdate() 来代替这种逻辑。”


Mod*_*ech 6

您可以包装setState一个返回诺言的函数,然后将该函数与await关键字一起使用,以使您的代码等待状态被应用。

就个人而言,我永远不会在真实代码中执行此操作,相反,我只会将状态更新后希望执行的代码放在setState回调中。

无神经,这是一个例子。

class MyComponent extends React.Component {

    function setStateSynchronous(stateUpdate) {
        return new Promise(resolve => {
            this.setState(stateUpdate, () => resolve());
        });
    }

    async function foo() {
        // state.count has value of 0
        await setStateSynchronous(state => ({count: state.count+1}));
        // execution will only resume here once state has been applied
        console.log(this.state.count);  // output will be 1
    }
} 
Run Code Online (Sandbox Code Playgroud)

在foo函数中,await关键字使代码执行暂停,直到setStateSynchronous解析了由其返回的promise为止,这仅在调用传递给回调的setState情况下发生,仅在应用状态时发生。因此,仅在应用状态更新后,执行才会到达console.log调用。

异步/等待的docs:
https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript /参考/操作员/等待