为什么要是用 setState
当我们希望通过点击一个按钮从而改变一个文本时,就需要使用到 setState方法,比如:
import React, { Component } from 'react'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
message: "Hello World"
}
}
render() {
return (
<div>
<h2>{this.state.message}</h2>
<button onClick={e => this.changeText()}>改变文本</button>
</div>
)
}
changeText() {
this.setState({
message: "文本已经被改变"
})
}
}
当我们调用setState时,会重新执行render函数,根据最新的State来创建ReactElement对象;然后再根据最新的ReactElement对象,对DOM进行修改
另外,setState方法是从Component中继承过来的
setState 异步更新
changeText() {
this.setState({
message: "文本已经被改变"
})
console.log(this.state.message); // Hello World
}
上面代码中再使用 setState 方法后,再打印 message,发现 message 没有被改变,由此可以看到 setState 是异步操作,在执行完setState之后不能够立刻拿到最新的state的结果
为什么要异步更新
设计成异步,可以显著提升性能,如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的,所以最好的办法是获取到多个更新,然后进行批量的更新 如果同步更新了state,但是还没有执行render函数,那么state和props不能保持同步,这样做会引起很多问题
如何获取更新后的值
1、setState接受两个参数:第二个参数是一个回调函数,这个回调函数会在更新后会执行
changeText() {
this.setState({
message: "文本已经被改变"
}, () => {
console.log(this.state.message); // 文本已经被改变
});
}
2、通过生命周期函数 componentDidUpdate
componentDidUpdate(prevProps, provState, snapshot) {
console.log(this.state.message);
}
同步 or 异步
setState 方法到底是同步还是异步分两种情况
-
在组件生命周期或React合成事件中,setState是异步
-
在setTimeout或者原生dom事件中,setState是同步
// setTimeout
changeText() {
setTimeout(() => {
this.setState({
message: "文本已经被改变"
});
console.log(this.state.message); // 文本已经被改变
}, 0);
}
// 原生DOM事件
componentDidMount() {
const btnEl = document.getElementById("btn");
btnEl.addEventListener('click', () => {
this.setState({
message: "文本已经被改变"
});
console.log(this.state.message); // 文本已经被改变
})
}
setState的合并
数据的合并
this.state = {
name: '小冯',
age: 19
}
// 通过setState去修改age,是不会对name产生影响的
this.setState({
age: 18
})
多个setState合并
this.state = {
counter: 0
}
increment() {
this.setState({
counter: this.state.counter + 1
});
this.setState({
counter: this.state.counter + 1
});
this.setState({
counter: this.state.counter + 1
});
}
setState 方法执行了3次,但是 counter 的值还是为1,这就是多个state进行合并
如果想要变为3,如何去做:传入一个函数
increment() {
this.setState((state, props) => {
return {
counter: state.counter + 1
}
})
this.setState((state, props) => {
return {
counter: state.counter + 1
}
})
this.setState((state, props) => {
return {
counter: state.counter + 1
}
})
}