setState是异步的
import React from 'react'
import ReactDOM from 'react-dom/client'
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 20,
age: 26,
}
}
increase() {
// setState是异步的
// 即使这里有多次调用setState,并且修改了不同的state,但最终render只执行了一次
this.setState({
count: this.state.count+1,
age: this.state.age+1,
})
this.setState({
count: this.state.count+2
})
this.setState({
count: this.state.count+3
})
this.setState({
count: this.state.count+4
})
}
render() {
console.log('render 执行了')
return (
<div>
<h2>{this.state.count}</h2>
<h2>{this.state.age}</h2>
<button onClick={() => this.increase()}><h2>click</h2></button>
</div>
)
}
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App></App>)
setState异步带来的问题
import React from 'react'
import ReactDOM from 'react-dom/client'
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 20,
}
}
increase() {
// 这里如果一秒钟只能快速点击两次使得increase被调用两次,
// 但是最后count只增加了1,因为它第二次读取到count的时候依然为21,产生bug
// 这里的setTimeout只是模拟setState的异步情况,真实情况中也是有可能出现这个问题的
// https://react.docschina.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
// let count = this.state.count
// setTimeout(() => {
// this.setState({
// count: count+1,
// })
// }, 1000);
// 简单情况下的解决方法: 每次获取state里面的值
setTimeout(() => {
this.setState({
count: this.state.count + 1,
})
}, 1000);
// 官方的解决方法:
// setTimeout(() => {
// this.setState((state, props) => ({
// count: state.count + 1
// }))
// }, 1000);
}
render() {
console.log('render 执行了')
return (
<div>
<h2>{this.state.count}</h2>
<h2>{this.state.age}</h2>
<button onClick={() => this.increase()}><h2>click</h2></button>
</div>
)
}
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App></App>)
state hook 也会出现这种bug:
import React from 'react'
import ReactDOM from 'react-dom/client'
function App(props) {
let [count, setCount] = React.useState(20)
function increase() {
// state hook 也会出现这种bug
// setTimeout(() => {
// setCount(count + 1)
// }, 1000);
// 解决方法:给react传一个用于更新state的回调函数
setTimeout(() => {
// react 确保回调函数的参数是最新的
setCount(preCount => {
return preCount + 1
})
}, 1000);
}
return (
<div>
<h2>{count}</h2>
<button onClick={() => increase()}>click</button>
</div>
)
}
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App></App>)
网友评论