有关React中使用setState的注意事项
详细信息请看官方文档
1 setState的使用方式
1.不要直接修改 State,应该使用setState
//此代码不会重新渲染组件
this.state.count = 1;
2.使用方式
(1)setState(updater, [callback])
updater为返回stateChange对象的函数: (state, props) => stateChange
接收的state和props被保证为最新的
(2)setState(stateChange, [callback])
stateChange为对象,
callback是可选的回调函数, 在状态更新且界面更新后才执行
(3)如何得到异步更新后的状态数据?
在setState()的callback回调函数中
(4)如何选择setState的方式呢?
对象方式是函数方式的简写方式
如果新状态不依赖于原状态 ===> 可以使用对象方式
如果新状态依赖于原状态 ===> 使用函数方式
小案例如下:
import React, { Component } from 'react';
class Count extends Component {
state = {
count: 0
}
add1 = () => {
//点击按钮count+1
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('add1 setState之后',this.state.count)
}
add2 = () => {
//点击按钮count+2
const count = this.state.count+2
this.setState({
count
})
console.log('add2 setState之后',this.state.count)
}
add3 = () => {
//点击按钮count+3
this.setState(state=>({count:state.count+3}),()=>{ //在状态更新且界面更新之后回调
console.log('add3 setState之后 callback',this.state.count)
})
}
render() {
const {count} = this.state
console.log('render:',count)
return (
<div>
<h1>Count组件当前count值:{count}</h1>
<button onClick={this.add1}>点击+1</button>
<button onClick={this.add2}>点击+2</button>
<button onClick={this.add3}>点击+3</button>
</div>
);
}
}
export default Count;
2 State 的更新可能是异步的
根据执行setState()的位置进行判断
如果在react控制的回调函数中: 生命周期函数、react事件监听回调,执行时异步的。
如果在非react控制的异步回调函数中: 如定时器回调、原生事件监听回调、promise.then(),执行是同步的。
小案例如下:
import React, { Component } from 'react';
class Count extends Component {
state = {
count: 0
}
countRef = React.createRef()
add1 = () => {
console.log('add1 setState之前',this.state.count)
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('add1 setState之后',this.state.count)
}
add2 = () => {
/**定时器中更新 */
setTimeout(()=>{
console.log('setTimeout setState之前',this.state.count)
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('setTimeout setState之后',this.state.count)
})
}
add3 = () => {
//原生DOM事件监听
const h1node = this.countRef.current
h1node.onclick = ()=>{
console.log('onclick setState之前',this.state.count)
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('onclick setState之后',this.state.count)
}
}
add4 = () => {
//promise
Promise.resolve().then(value=>{
console.log('Promise setState之前',this.state.count)
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('Promise setState之后',this.state.count)
})
}
add5 = () => {
//setState更新使用函数形式
console.log('函数形式 setState之前',this.state.count)
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('函数形式 setState之后',this.state.count)
console.log('函数形式 setState之前2',this.state.count)
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('函数形式 setState之后2',this.state.count)
}
add6 = () => {
//setState更新使用对象形式
console.log('对象形式 setState之前',this.state.count)
this.setState({count:this.state.count+1})
console.log('对象形式 setState之后',this.state.count)
console.log('对象形式 setState之前2',this.state.count)
this.setState({count:this.state.count+1})
console.log('对象形式 setState之后2',this.state.count)
}
add7 = () => {
//setState更新使用函数与对象形式
console.log('对象形式 setState之前',this.state.count)
this.setState({count:this.state.count+1})
console.log('对象形式 setState之后',this.state.count)
console.log('函数形式 setState之前',this.state.count)
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('函数形式 setState之后',this.state.count)
}
componentDidMount(){
/**生命周期中更新 */
console.log('componentDidMount setState之前',this.state.count)
this.setState((state) => {
return {
count:state.count+1
}
})
console.log('componentDidMount setState之后',this.state.count)
}
render() {
const {count} = this.state
console.log('render:',count)
return (
<div>
<h1 ref={this.countRef}>Count组件当前count值:{count}</h1>
<button onClick={this.add1}>点击+1</button>
<button onClick={this.add2}>定时器+1</button>
<button onClick={this.add3}>原生onclick+1</button>
<button onClick={this.add4}>promise+1</button>
<button onClick={this.add5}>函数形式+1</button>
<button onClick={this.add6}>对象形式+1</button>
<button onClick={this.add7}>函数与对象形式+1</button>
</div>
);
}
}
export default Count;
3 State 的更新会被合并
关于异步的setState(),多次调用, 如何处理?
setState({}): (对象形式)合并更新一次状态, 只调用一次render()更新界面 —状态更新和界面更新都合并了
setState(fn): (函数形式)更新多次状态, 但只调用一次render()更新界面 —状态更新没有合并, 界面更新合并了。
- 本文作者: étoile
- 版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!