react中setState方法到底是異步還是同步,其實這個是分在什么條件下是異步或者同步,
1.先來回顧一下react組件中改變state的幾種方式:
import React, { Component } from 'react'
class Index extends Component {
state={
count:1
}
test1 = () => {
// 通過回呼函式的形式
this.setState((state,props)=>({
count:state.count+1
}));
console.log('test1 setState()之后',this.state.count);
}
test2 = () => {
// 通過物件的方式(注意:此方法多次設定會合并且只呼叫一次!)
this.setState({
count:this.state.count+1
});
console.log('test2 setState()之后',this.state.count);
}
test3 = () => {
// 不能直接修改state的值,此方法強烈不建議!!!因為不會觸發重新render
this.state.count += 1;
}
test4 = () => {
// 在第二個callback拿到更新后的state
this.setState({
count:this.state.count+1
},()=>{// 在狀態更新且頁面更新(render)后執行
console.log('test4 setState()之后',this.state.count);
});
}
render() {
console.log('render');
return (
<div>
<h1>currentState:{this.state.count}</h1>
<button onClick={this.test1}>測驗1</button>
<button onClick={this.test2}>測驗2</button>
<button onClick={this.test3} style={{color:'red'}}>測驗3</button>
<button onClick={this.test4}>測驗4</button>
</div>
)
}
}
export default Index;
2.setState()更新狀態是異步還是同步:
需要判斷執行setState的位置
同步:在react控制的回呼函式中:生命周期鉤子/react事件監聽回呼
import React, { Component } from 'react'
class Index extends Component {
state={
count:1
}
/*
react事件監聽回呼中,setState()是異步狀態
*/
update1 = () => {
console.log('update1 setState()之前',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('update1 setState()之后',this.state.count);
}
/*
react生命周期鉤子中,setState()是異步更新狀態
*/
componentDidMount() {
console.log('componentDidMount setState()之前',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('componentDidMount setState()之后',this.state.count);
}
render() {
console.log('render');
return (
<div>
<h1>currentState:{this.state.count}</h1>
<button onClick={this.update1}>測驗1</button>
<button onClick={this.update2}>測驗2</button>
</div>
)
}
}
export default Index;
異步:非react控制的異步回呼函式中:定時器回呼/原生事件監聽回呼/Promise
import React, { Component } from 'react'
class Index extends Component {
state={
count:1
}
/*
定時器回呼
*/
update1 = () => {
setTimeout(()=>{
console.log('setTimeout setState()之前',this.state.count);//1
this.setState((state,props)=>({
count:state.count+1
}));
console.log('setTimeout setState()之后',this.state.count);//2
});
}
/*
原生事件回呼
*/
update2 = () => {
const h1 = this.refs.count;
h1.onclick = () => {
console.log('onClick setState()之前',this.state.count);//1
this.setState((state,props)=>({
count:state.count+1
}));
console.log('onClick setState()之后',this.state.count);//2
}
}
/*
Promise回呼
*/
update3 = () => {
Promise.resolve().then(value=>{
console.log('Promise setState()之前',this.state.count);//1
this.setState((state,props)=>({
count:state.count+1
}));
console.log('Promise setState()之后',this.state.count);//2
});
}
render() {
console.log('render');
return (
<div>
<h1 ref='count'>currentState:{this.state.count}</h1>
<button onClick={this.update1}>測驗1</button>
<button onClick={this.update2}>測驗2</button>
<button onClick={this.update3}>測驗3</button>
</div>
)
}
}
export default Index;
3.setState()多次呼叫的問題:
異步的setState()
(1)多次呼叫,處理方法:
setState({}):合并更新一次狀態,只呼叫一次render()更新界面,多次呼叫會合并為一個,后面的值會覆寫前面的值,
setState(fn):更新多次狀態,只呼叫一次render()更新界面,多次呼叫不會合并為一個,后面的值會覆寫前面的值,
import React, { Component } from 'react'
class Index extends Component {
state={
count:1
}
update1 = () => {
console.log('update1 setState()之前',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('update1 setState()之后',this.state.count);
console.log('update1 setState()之前2',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('update1 setState()之后2',this.state.count);
}
update2 = () => {
console.log('update2 setState()之前',this.state.count);
this.setState({
count:this.state.count+1
});
console.log('update2 setState()之后',this.state.count);
console.log('update2 setState()之前2',this.state.count);
this.setState({
count:this.state.count+1
});
console.log('update2 setState()之后2',this.state.count);
}
update3 = () => {
console.log('update3 setState()之前',this.state.count);
this.setState({
count:this.state.count+1
});
console.log('update3 setState()之后',this.state.count);
console.log('update3 setState()之前2',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));// 這里需要注意setState傳參為函式模式時,state會確保拿到的是最新的值
console.log('update3 setState()之后2',this.state.count);
}
update4 = () => {
console.log('update4 setState()之前',this.state.count);
this.setState((state,props)=>({
count:state.count+1
}));
console.log('update4 setState()之后',this.state.count);
console.log('update4 setState()之前2',this.state.count);
this.setState({
count:this.state.count+1
});// 這里需要注意的是如果setState傳參為物件且在最后,那么會與之前的setState合并
console.log('update4 setState()之后2',this.state.count);
}
render() {
console.log('render');
return (
<div>
<h1>currentState:{this.state.count}</h1>
<button onClick={this.update1}>測驗1</button>
<button onClick={this.update2}>測驗2</button>
<button onClick={this.update3}>測驗3</button>
<button onClick={this.update4}>測驗4</button>
</div>
)
}
}
export default Index;
(2)如何得到setState異步更新后的狀態資料:
在setState()的callback回呼函式中
4.react中常見的setState面試題(setState執行順序)
import React, { Component } from 'react'
// setState執行順序
class Index extends Component {
state={
count:0
}
componentDidMount() {
this.setState({count:this.state.count+1});
this.setState({count:this.state.count+1});
console.log(this.state.count);// 2 => 0
this.setState(state=>({count:state.count+1}));
this.setState(state=>({count:state.count+1}));
console.log(this.state.count);// 3 => 0
setTimeout(() => {
this.setState({count:this.state.count+1});
console.log('setTimeout',this.state.count);// 10 => 6
this.setState({count:this.state.count+1});
console.log('setTimeout',this.state.count);// 12 => 7
});
Promise.resolve().then(value=>{
this.setState({count:this.state.count+1});
console.log('Promise',this.state.count);// 6 => 4
this.setState({count:this.state.count+1});
console.log('Promise',this.state.count);// 8 => 5
});
}
render() {
console.log('render',this.state.count);// 1 => 0 // 4 => 3 // 5 => 4 // 7 => 5 // 9 => 6 // 11 => 7
return (
<div>
<h1>currentState:{this.state.count}</h1>
<button onClick={this.update1}>測驗1</button>
<button onClick={this.update2}>測驗2</button>
<button onClick={this.update3}>測驗3</button>
<button onClick={this.update4}>測驗4</button>
</div>
)
}
}
export default Index;
總結:react中setState()更新狀態的2種寫法
1)setState(updater,[callback])
updater:為回傳stateChange物件的函式:(state,props)=>stateChange,接收的state和props都保證為最新的
2)setState(stateChange,[callback])
stateChange為物件,callback是可選的回呼函式,在狀態更新且界面更新后才執行
注意:
物件是函式方式的簡寫方式
如果新狀態不依賴于原狀態,則使用物件方式;
如果新狀態依賴于原狀態,則使用函式方式;
如果需要在setState()后獲取最新的狀態資料,在第二個callback函式中獲取
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/161546.html
標籤:JavaScript
上一篇:一起學Vue之樣式系結
下一篇:用js寫一個滑鼠坐標實體
