一.为什么使用setState?
1)作用
为了管理和维护React中的状态,除了Redux转态管理器,React内部提供了setState来进行组件内的状态管理。
2)基本使用
a.向setState中传入一个对象对已有的state进行更改
b.setState可以接受一个函数作为参数,这个函数返回也是一个对象,同上,但是该函数参数为state的前一个状态以及props
c.setState可以接受两个参数,第一个可以是a,b两种情况。第二个参数是回调函数,始终是执行完setState后再执行回调函数。
/*
void setState (
function|object nextState,
[function callback]
)
*/
class Home extend React.component{
constructor(props){
super(props);
this.state{
number:1,
}
}
//a
changeA=()=>{
this.setState({
number:2,
})
}
//b
changeB=()=>{
this.setState((preState,props)=>{
return ({
number:preState.number+1,
})
})
}
//c
changeC=()=>{
this.setState({
number:3,
},callback=>{
console.log('执行完setState后,再执行这个回调函数')
})
}
}
二.setState到底干了什么?
1)执行setState()后做了什么?
setState通过一个队列机制实现state的更新,当执行setState()的时候,会将需要更新的state合并之后放入状态队列,而不会立即更新this.state(可以和浏览器的事件队列类比)。如果我们不使用setState
而是使用this.state.key
来修改,会修改但是将不会触发组件的re-render(不渲染)。
2)注意:
a.不要使用this.state直接修改state,(因为修改后不render,导致显示的内容和实际存在的state不一致),用setState代替;
b.state更新可能是异步的。不要用this.setState({this.state.number+this.props.xxx}),由于异步可能获取不到你想要的内容。此时需要使用上面所说第一个问题基本使用的b方法。
c.state更新会被合并。当你调用 setState(), React 将合并你提供的对象到当前的状态中。所以当State是一个多键值的结构时,可以单独更新其中的一个,此时会进行“差分”更新,不会影响其他的属性值。
三.setState是同步的还是异步的?
由 React 控制的事件处理过程 setState 不会同步更新 this.state!
也就是说,在 React 控制之外的情况, setState 会同步更新 this.state!(如下边例子setTimeOut()函数内)
但大部份的使用情况下,我们都是使用了 React 库中的表单组件,例如 select、input、button 等等,它们都是 React 库中人造的组件与事件,是处于 React 库的控制之下,比如组件原生 onClick 都是经过 React 包装。在这个情况下,setState 就会以异步的方式执行。
class page extends Component {
state = {
name: 'xxx',
age: 20,
}
onClickDiv = () => {
this.setState((prevState, props) => {
console.log('11-------', prevState);
return ({
name: 'xxx11',
})
})
this.setState((prevState, props) => {
console.log('22-------', prevState);
return ({
name: 'xxx22',
age: 30,
})
})
console.log('异步还是同步1111????');
setTimeout(() => {
this.setState({ name: 'xxx33' })
console.log('异步还是同步2222????');
this.setState((prevState, props) => {
console.log('33-------', prevState);
return ({
name: 'xxx44',
})
})
console.log('异步还是同步3333????', this.state.name);
this.setState((prevState, props) => {
console.log('44-------', prevState);
return ({
name: 'xxxx55',
})
})
console.log('异步还是同步4444????', this.state.name);
this.setState({ name: 'xxxx66' }, () => {
console.log('完成');
})
console.log('异步还是同步5555????', this.state.name);
this.state.name = 'xxxx77'
}, 2000);
}
render() {
const { name, age } = this.state
console.log(name, age);
return (
<div onClick={() => this.onClickDiv()}>
{name}nihao{age}
<div className={styles.contentMap}>
<div id="map" className={styles.map}></div>
</div>
</div>
)
}
}
/*
====================点击第1次-----setTimeOut外表现异步,内表现同步=============
异步还是同步1111????
11------- {name: "999888", age: 20}
22------- {name: "xxx11", age: 20}
xxx22 30
xxx33 30
异步还是同步2222????
33------- {name: "xxx33", age: 30}
xxx44 30
异步还是同步3333???? xxx44
44------- {name: "xxx44", age: 30}
xxxx55 30
异步还是同步4444???? xxxx55
xxxx66 30
完成
异步还是同步5555???? xxxx66
====================点击第2次--this.state能修改但未render=============
异步还是同步1111????
11------- {name: "xxxx77", age: 30}
...
*/
参考:https://www.jianshu.com/p/a883552c67de