案例1
观察如下代码,点击+按钮后,控制台和页面效果如下
import React,{useRef, useState} from "react"
const Page1 = () => {
const [num,setNum] = useState(0)
const divRef = useRef(null)
const addNum = () => {
setNum(num+1)
console.log(divRef.current.innerText)
}
return (
<div>
<div ref={divRef}>num:{num}</div>
<button onClick={addNum}>+</button>
</div>
)
}
export default Page1
结论1 react的state在发生更新后,并不是同步渲染dom到页面,也就是dom的渲染也是异步执行。
案例2
const [num,setNum] = useState(0)
const addNum = () => {
console.log('begin',num)
setNum(num+1)
console.log('end',num)
}
<div onClick={addNum}></div>
结论2 react的setState是异步执行,因此执行setNum后,无法获取最新的num.
案例3
观察代码输出,发现num更新后,可以拿到num的最新数据,
import React,{useRef, useState} from "react"
const Page1 = () => {
const [num,setNum] = useState(0)
const addNum = () => {
setNum(e=>{
let newVal = e+1
console.log(newVal)
return newVal
})
}
return (
<div>
<div>num:{num}</div>
<button onClick={addNum}>+</button>
</div>
)
}
export default Page1
分析
查看setStata函数参数的ts定义,可以发现setState的参数可以传递两种类型
-
传递的数据类型
-
函数,函数的参数是state,并且setState传递函数可以实现同步更新state
type React.SetStateAction<S> = S | ((prevState: S) => S)
验证
const [num,setNum] = useState(0)
const addNum = () => {
console.log('1')
setNum(e=>{
let newV = e+1
console.log('2')
return newV
})
console.log('3')
}
<div onClick={addNum}></div>
页面打印输出1,2,3,符合要求。
结论3 react的setState传递变量是异步执行操作,而传递函数可以实现同步更新state。还可以获取获取最新的state。
案例4
import React, { useState } from 'react';
const BatchUpdateExample = () => {
console.log('app load')
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const handleClick = () => {
setCount1(count1 + 1);
setCount2(count2 + 1);
};
return (
<div>
<p>Count1: {count1}</p>
<p>Count2: {count2}</p>
<button onClick={handleClick}>Increment</button>
</div>
);
};
观察上述代码,页面render几次?答案是1次。react批量更新机制让count1和count2的更改只渲染一次。
无批量更新
无批量更新机制时,n个state发生更改,页面render了n次
graph TD
收集依赖state1 --> 更新1 --> 渲染state1到页面
收集依赖state2 --> 更新2 --> 渲染state2到页面
... --> .... --> .....
批量更新
graph TD
收集依赖state1 --> 添加更新队列--> 批量更新--> 批量渲染dom
收集依赖state2 --> 添加更新队列--> 批量更新--> 批量渲染dom
收集依赖staten --> 添加更新队列--> 批量更新--> 批量渲染dom
案例5
一次按钮点击,同时执行三次setState,页面最后显示?
import React,{useRef, useState} from "react"
const Page2 = () => {
const [num,setNum] = useState(0)
const addNum = () => {
setNum(num+1)
setNum(num+2)
setNum(num+3)
}
return (
<div>
<div>num:{num}</div>
<button onClick={addNum}>+</button>
</div>
)
}
export default Page2
结果是3,setState对同一份数据批量修改,只有最后一次修改会被执行。
结论:对同一个state执行多次更新操作,react永远只执行最后一次的setState更新。
如何让多个setState同时生效?只需要setState传递函数即可。如下num最新值是6
setNum(num=>num+1)
setNum(num=>num+2)
setNum(num=>num+3)