任务优先级:
在React18之前,所有的更新任务都被视为急迫的任务
在React18诞生了concurrentMode模式,在这个模式下,渲染是可以中断,低优先级任务,可以让高优先级的任务先更新渲染。
可以说React18更青睐于良好的用户体验。从concurrentMode到susponse再到startTransition无疑都是围绕着更优质的用户体验展开
任务优先级场景:
有一个input表单,并且有一个大量数据的列表,通过表单输入内容,对列表数据进行搜索,过滤。那么在这种情况下,就存在了多个并发的更新任务。分别为
第一种:input表单要实时获取状态,所以是受控的,那么更新input的内容,就要触发更新任务。
第二种:input内容改变,过滤列表,重新渲染列表也是一个任务。
当过滤列表过多时,输入内容就会产生卡顿
第一种类型的更新,在输入的时候,希望是的视觉上马上呈现变化,高优先级。
第二种类型的更新就是根据数据的内容,去过滤列表中的数据,渲染列表,这个种类的更新,和上一种比起来优先级就没有那么高。
与定时器的区别:
1.由于setTimeout本身也是一个宏任务,而每一次触发dom回调也是宏任务,所以setTimeout还是会影响页面的交互体验。
在concurrent Mode模式下,startTransition是可以中断渲染的,所以它不会让页面卡顿,React让这些任务,在浏览器空闲时间执行
和window.requestAnimation类似
2.startTransition的回调函数是同步执行的。
在startTransition之中任何更新,都会标记上transition,React将在更新的时候,判断这个标记来决定是否完成此次更新。
所以Transition可以理解成比setTimeout更早的更新。
但是同时要保证ui的正常响应,在性能好的设备上,transition两次更新的延迟会很小,但是在慢的设备上,延时会很大,但是不会影响UI的响应。
(1)开启concurrent Mode模式:
import ReactDOM from 'react-dom'
const root = ReactDOM.createRoot(document.getElementById('app'))
root.render(<App/>)
(2)使用startTranstion
const handleChange=()=>{
setInputValue(e.target.value) /* 高优先级任务 —— 改变搜索条件 */
React.startTransition(()=>{ /* 低优先级任务 —— 改变搜索过滤后列表状态 */
setSearchQuery(e.target.value)
})
}
代码示例:
/* 模拟数据 */
const mockDataArray = new Array(10000).fill(1)
/* 高量显示内容 */
function ShowText({
query }){
const text = 'asdfghjk'
let children
if(text.indexOf(query) > 0 ){
/* 找到匹配的关键词 */
const arr = text.split(query)
children = <div>{
arr[0]}<span style={
{
color:'pink' }} >{
query}</span>{
arr[1]} </div>
}else{
children = <div>{
text}</div>
}
return <div>{
children}</div>
}
/* 列表数据 */
function List ({
query }){
console.log('List渲染')
return <div>
{
mockDataArray.map((item,index)=><div key={
index} >
<ShowText query={
query} />
</div>)
}
</div>
}
/* memo 做优化处理 */
const NewList = memo(List)
========================================================================================================
export default function App(){
const [ value ,setInputValue ] = React.useState('')
const [ isTransition , setTransion ] = React.useState(false)
const [ query ,setSearchQuery ] = React.useState('')
const handleChange = (e) => {
/* 高优先级任务 —— 改变搜索条件 */
setInputValue(e.target.value)
if(isTransition){
/* transition 模式 */
React.startTransition(()=>{
/* 低优先级任务 —— 改变搜索过滤后列表状态 */
setSearchQuery(e.target.value)
})
}else{
/* 不加优化,传统模式 */
setSearchQuery(e.target.value)
}
}
return <div>
<button onClick={
()=>setTransion(!isTransition)} >{
isTransition ? 'transition' : 'normal'} </button>
<input onChange={
handleChange}
placeholder="输入搜索内容"
value={
value}
/>
<NewList query={
query} />
</div>
}