首先了解下批量更新,在以下两种情况下,只会渲染一次
class有状态组件中的this.setState与hooks中useState,两种方法已经做了批量更新的处理
class组件
class index extends React.Component{
constructor(prop){
super(prop)
this.state = {
a:1,
b:2,
c:3,
}
}
handerClick=()=>{
const { a,b,c } :any = this.state
this.setState({ a:a+1 })
this.setState({ b:b+1 })
this.setState({ c:c+1 })
}
render= () => <div onClick={this.handerClick} />
}
hook中
无状态组件中
const [ a , setA ] = useState(1)
const [ b , setB ] = useState({})
const [ c , setC ] = useState(1)
const handerClick = () => {
setB( { ...b } )
setC( c+1 )
setA( a+1 )
}
但是 批量更新在某些情况下会失效,造成多次渲染 ,例如setTimeout,Promise.then(fn), fetch回调,xhr网络回调等,如下例子会渲染3次
handerClick=()=>{
setTimeout(() => {
this.setState({ a:a+1 })
this.setState({ b:b+1 })
this.setState({ c:c+1 })
}, 0)
}
const handerClick = () => {
Promise.resolve().then(()=>{
setB( { ...b } )
setC( c+1 )
setA( a+1 )
})
}
为了避免此类情况发生,我们需要引入unstable_batchedUpdates 进行手动合并,如下
handerClick=()=>{
setTimeout(() => {
unstable_batchedUpdates(()=>{
this.setState({ a:a+1 })
this.setState({ b:b+1 })
this.setState({ c:c+1 })
})
}, 0)
}
const handerClick = () => {
Promise.resolve().then(()=>{
unstable_batchedUpdates(()=>{
setB( { ...b } )
setC( c+1 )
setA( a+1 )
})
})
}