根据docs中的解释:
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
由于alert
值是之前的值,因此使用alert value:1
为setState()
提供的替代方案是什么。
Stackoverflow上几乎没有与此问题相似的问题,但没有我能找到正确答案的地方。
答案 0 :(得分:49)
正如您从文档中读到的那样,没有同步替代方案,所描述的原因是性能提升。
但是我假设你想在改变状态后执行一个动作,你可以通过以下方式实现:
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")
);
&#13;
<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>
&#13;
答案 1 :(得分:5)
您可以将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
}
}
在foo函数中,关键字await
导致代码执行暂停,直到setStateSynchronous
返回的承诺被解决为止,只有在调用传递给setState
的回调时才发生,仅在应用状态后才会发生。因此,仅在应用状态更新后,执行才会到达console.log调用。
async / await的文档:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
答案 2 :(得分:2)
不,没有。 React将在其认为合适时更新状态,执行诸如将setState
调用一起批处理以提高效率。您可能感兴趣的是,您可以将一个函数传递给setState
而不是之前的状态,因此您可以选择一个对前一个状态有充分了解的新状态。
答案 3 :(得分:2)
如果这是必需的,我建议在你的setState函数中使用回调(我还建议使用函数setState)。
在状态更新后将调用回调。
例如,您的示例是
public ActionResult Products_Read([DataSourceRequest] DataSourceRequest request)
{
return Json(productService.Read().ToDataSourceResult(request));
}
根据此处的文档:https://facebook.github.io/react/docs/react-component.html#setstate
注意:官方文档说,“通常我们建议使用componentDidUpdate()代替这种逻辑。”
答案 4 :(得分:0)
对你的问题的简短回答是 - 不,反应没有同步方法setState
。
答案 5 :(得分:0)
是的,有一种方法可以用来制作我们的同步setState。但它的表现可能并不像通常那样好 例如,我们有
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
data: 0
};
}
changeState(){
console.log('in change state',this.state.data);
this.state.data = 'new value here'
this.setState({});
console.log('in change state after state change',this.state.data);
}
render() {
return (
<div>
<p>{this.state.data}</p>
<a onClick={this.changeState}>Change state</a>
</div>
);
}
}
在此示例中,我们首先更改状态,然后渲染我们的组件。
答案 6 :(得分:0)
这听起来很怪异,但是setState可以在react中同步工作。 为何如此?这是我创建来演示的POC。
粘贴唯一的应用JS代码。
也许我可能遗漏了一些东西,但这实际上是在我了解这种效果的应用程序中发生的。
更正我,如果我不知道在React中会发生这种行为。 当主线程上有多个setState时,setState将运行main上所有setState的批处理。当异步函数中放入相同的内容时,方案是不同的。
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
counter: 0
}
this.asyncMethod = this.asyncMethod.bind(this);
this.syncMethod = this.syncMethod.bind(this);
}
asyncMethod() {
console.log("*************************")
console.log("This is a async Method ..!!")
this.setState({
counter: this.state.counter + 1
}, () => {
console.log("This is a async Method callback of setState. value of counter is---", this.state.counter);
})
console.log("This is a async Method on main thread. value of counter is---", this.state.counter);
console.log("*************************")
}
syncMethod() {
var that = this;
console.log("*************************")
console.log("This is a sync Method ..!!")
that.setState({counter: "This value will never be seen or printed and render will not be called"});
that.setState({counter: "This is the value which will be seen in render and render will be called"});
setTimeout(() => {
that.setState({counter: "This is part is synchronous. Inside the async function after this render will be called"});
console.log("setTimeout setState");
that.setState({counter: "This is part is aslso synchronous. Inside the async function after this render will be called"});
}, 10)
console.log("This is a sync Method on Main thread. value of counter is---", this.state.counter);
console.log("*************************")
}
render() {
console.log("Render..!!",this.state.counter);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
</header>
<button onClick={this.asyncMethod}>AsyncMethod</button>
<button onClick={this.syncMethod}>SyncMethod</button>
</div>
);
}
}
export default App;
答案 7 :(得分:0)
改为使用React Hooks:
function MyComponent() {
const [cnt, setCnt] = useState(0)
const updateState = () => {
setCnt(cnt + 1)
}
useEffect(() => {
console.log('new state', cnt)
}, [cnt])
return (
<div>
<button onClick={updateState}>Change state</button>
</div>
)
}
答案 8 :(得分:-1)
我能够通过将代码包装在setState
中来欺骗React同步调用setTimeout(() => {......this.setState({ ... });....}, 0);
。由于setTimeout
将内容放在JavaScript事件队列的末尾,我认为React检测到setState在其中,并且知道它不能依赖于批量setState
调用(这将被添加到队列的结尾)。