在React中,我们使用setState
来更新组件的状态。 setState
是一个异步过程,因此如果我们在同一函数中有多个setState
,则为componentDidMount
。
问题:内部如何处理更新的批处理?
场景1:
在class TodoApp extends React.Component {
constructor(props) {
super(props)
var state = { count: 0 };
Object.defineProperty(this, 'state', {
set: function(value) { console.log('called', value.count); state = value },
get: function() { return state; }
})
}
test() {
for (let i = 0; i< 1000; i++) {
this.setState({ count: i });
}
}
componentDidMount() {
this.test();
}
render() {
return (
<div>
{ this.state.count }
</div>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
的for循环中更新状态,但执行周期相同。
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
componentDidMount
方案2:
在class TodoApp extends React.Component {
constructor(props) {
super(props)
var state = { count: 0 };
Object.defineProperty(this, 'state', {
set: function(value) { console.log('called', value.count); state = value },
get: function() { return state; }
})
}
test() {
for (let i = 0; i< 1000; i++) {
this.setState({ count: i });
}
}
componentDidMount() {
setTimeout(this.test.bind(this), 0);
}
render() {
return (
<div>
{ this.state.count }
</div>
)
}
}
ReactDOM.render(<TodoApp />, document.querySelector("#app"))
中的for循环中更新状态,但是在不同的执行周期中进行。
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
getImageSize(url){
var img = new Image()
img.src = url
img.onload = function(){
return [img.width, img.height]
}
}
getImageUrl(obj){
let vm = this
let reader = new FileReader()
reader.readAsDataURL(obj)
reader.onload = function() {
return reader.result
}
}
async getImageSize(imgObj){
let base64URI = await this.getImageUrl(imgObj)
let size = await this.getImageSize(base64URI)
return size
}
beforeuploadImage(event){
let imgsize = this.getImageSize(imgObj)
imgsize = imgsize.split(",")
console.log(imgsize[0], imgsize[1])
}
如果您注意到方案1和2,则在方案1中仅执行2次更新(假定1为初始更新,而其他为final )。但是,在方案2中,状态会针对每个setState进行更改/更新。
那么异步更新如何工作?什么定义了批量更新操作?
答案 0 :(得分:4)
如果您在React事件处理程序中,它们将被一起批处理。 React批处理在React事件处理程序期间完成的所有setState,并 在退出自己的浏览器事件处理程序之前应用它们。
setTimeout不是React事件处理程序,因此React不会在setTimeout回调(方案2)中批处理状态更新。
参考:https://github.com/facebook/react/issues/10231#issuecomment-316644950
答案 1 :(得分:0)
如果要使用setState进行batchUpdate,则应使用同步setState。有一种预定义的方法可以使我们的setState同步。
我对您的解释很困惑,但是根据react文档的说法,我们不应该将多个状态设置为一个函数。因为它将导致每次重新渲染。但这不是一个好方法。
所以这是您要设置的计数状态,但要以同步方式进行。 那么您可能更喜欢
this.setState(prevState=>{
const {count}=prevState;
//perform any action with this count state and at the end
return {...prevState,count};})
希望这种方法可能对您有所帮助。