为什么使用
setState()
?setState()
会对一个组件的state
对象安排一次更新。当state
改变了,该组件就会重新渲染。开发中我们不能直接通过修改state
当中的值来让界面发生更新,因为修改了state
后希望的是 React 根据最新的state
值来进行更新界面,但是这种方式 React 并不知道数据发生了变化,所以必须通过setState()
来告诉 React 数据已经发生了变化需要更新界面。
一、setState 可能是异步更新
class App extends Component {
constructor() {
super();
this.state = {
number: 0
}
}
render() {
return (
<div>
<h2>{this.state.number}</h2>
<button onClick={e => this.addText()}>+1</button>
</div>
)
}
addText() {
this.setState({
number: this.state.number + 1
});
console.log(this.state.number); // 0
}
}
当调用 this.setState({ number: this.state.number + 1 })
后所打印得到的值依旧为 0。
获取异步更新后的数据:
class App extends Component {
constructor() {
super();
this.state = {
number: 0
}
}
render() {
return (
<div>
<h2>{this.state.number}</h2>
<button onClick={e => this.addText()}>+1</button>
</div>
)
}
// 方式二:通过声明周期函数获取异步更新的值
componentDidUpdate() {
console.log(this.state.number); // 1
}
addText() {
this.setState({
number: this.state.number + 1
}, () => { // 方式一:通过 setState 的回调函数获取异步更新的值
console.log(this.state.number); // 1
});
}
}
二、setState 可能是同步更新
- 当 setState() 方法在 setTimeout() 中执行:
class App extends Component {
constructor() {
super();
this.state = {
number: 0
}
}
render() {
return (
<div>
<h2>{this.state.number}</h2>
<button onClick={e => this.addText()}>+1</button>
</div>
)
}
addText() {
setTimeout(() => {
this.setState({
number: this.state.number + 1
});
console.log(this.state.number); // 1
}, 0);
}
}
- 当 setState() 方法在原生 DOM 事件中执行:
class App extends Component {
constructor() {
super();
this.state = {
number: 0
}
}
componentDidMount() {
// 原生点击事件
const btnEl = document.getElementById('btn');
btnEl.addEventListener('click', () => {
this.setState({
number: this.state.number + 1
});
console.log(this.state.number); // 1
})
}
render() {
return (
<div>
<h2>{this.state.number}</h2>
<button id='btn'>+1</button>
</div>
)
}
}
一般情况下,
setState()
方法在组件生命周期或 React 合成事件中是异步更新的;在setTimeout()
或者原生 DOM 事件中是同步的。
三、setState 数据的合并
// this.state 当中有两个属性
constructor() {
super();
this.state = {
number: 0,
name: 'zhangsan'
}
}
/* --------------- */
// 更新 state
this.setState({
number: 10
});
当 constructor
中的 this.state
有多个属性时,调用 this.setState()
方法更新其中一条 number
属性后,不会将之前的 name
属性覆盖,而是单独修改 number
属性,等同于:
Object.assign({}, this.state, { number: 10 })
四、setState 本身的合并
class App extends Component {
constructor() {
super();
this.state = {
number: 0
}
}
render() {
return (
<div>
<h2>{this.state.number}</h2>
<button onClick={e => this.addText()}>+1</button>
</div>
)
}
addText() {
// setState 本身被合并
// this.setState({
// number: this.state.number + 1
// });
// this.setState({
// number: this.state.number + 1
// });
// this.setState({
// number: this.state.number + 1
// });
/* 最终结果还是 1 */
// setState 合并时进行累加
this.setState((prevState, props) => {
return {
number: prevState.number + 1
}
})
this.setState((prevState, props) => {
return {
number: prevState.number + 1
}
})
this.setState((prevState, props) => {
return {
number: prevState.number + 1
}
})
/* 最终结果为 3 */
}
}