使用并发模式
React 18引入并发模式,它允许你将标记更新作为一个transitions,这会告诉React它们可以被中断执行。这样可以把紧急的任务先更新,不紧急的任务后更新。
1. 使用startTransition
startTransition可以让你在不阻塞UI的情况下更新state:
jsx
import { startTransition, useState } from 'react'
function List({query}) {
const items = []
const word = "hello world"
if(query!='' && word.includes(query)) {
const splitWord = word.split(query)
// 制造一个非常耗时的任务
for (let i = 0; i < 20000; i++) {
items.push(
<li key={i}>{splitWord[0]}<span style={{color:'red'}}>{query}</span>{splitWord[1]}</li>
)
}
}else{
for (let i = 0; i < 20000; i++) {
items.push(
<li key={i}>{word}</li>
)
}
}
return (
<ul>
{items}
</ul>
)
}
function App() {
const [msg, setMsg] = useState('')
const [query, setQuery] = useState(msg)
const handleChange = (e)=>{
// 紧急任务
setMsg(e.target.value)
// 非紧急任务
startTransition(()=>{
setQuery(e.target.value)
})
}
return (
<div>
<input type="text" onChange={handleChange} value={msg} />
<List query={query}/>
</div>
)
}
export default App
运行效果: 可以看到输入框不再受到影响,输入不再卡顿,因为输入框是一个受控组件,它需要jsx渲染完成才能在页面上显示最新结果,使用startTransition表示了不紧急的任务,提高了输入体验。
2. 使用useTransition
useTransition钩子函数提供更好的并发体验:
jsx
import { useState, useTransition } from 'react'
function List({query}) {
const items = []
const word = "hello world"
if(query!='' && word.includes(query)) {
const splitWord = word.split(query)
// 制造一个非常耗时的任务
for (let i = 0; i < 20000; i++) {
items.push(
<li key={i}>{splitWord[0]}<span style={{color:'red'}}>{query}</span>{splitWord[1]}</li>
)
}
}else{
for (let i = 0; i < 20000; i++) {
items.push(
<li key={i}>{word}</li>
)
}
}
return (
<ul>
{items}
</ul>
)
}
function App() {
const [msg, setMsg] = useState('hello')
const [query, setQuery] = useState('hello')
const [pendding, startTransition] = useTransition()
const handleChange = (e)=>{
// 紧急任务
setMsg(e.target.value)
// 非紧急任务
startTransition(()=>{
setQuery(e.target.value)
})
}
return (
<div>
<input type="text" onChange={handleChange} value={msg} />
{pendding && "loading..."}
<List query={query}/>
</div>
)
}
export default App
3. 使用useDeferredValue
useDeferredValue只返回一个延迟对象:
jsx
import { useDeferredValue, useState } from 'react'
function List({query}) {
const items = []
const word = "hello world"
if(query!='' && word.includes(query)) {
const splitWord = word.split(query)
// 制造一个非常耗时的任务
for (let i = 0; i < 20000; i++) {
items.push(
<li key={i}>{splitWord[0]}<span style={{color:'red'}}>{query}</span>{splitWord[1]}</li>
)
}
}else{
for (let i = 0; i < 20000; i++) {
items.push(
<li key={i}>{word}</li>
)
}
}
return (
<ul>
{items}
</ul>
)
}
function App() {
const [msg, setMsg] = useState('hello')
// msg的延迟生效的副本对象, 哪里用query,哪里就是延迟生效
const query= useDeferredValue(msg)
const handleChange = (e)=>{
// 紧急任务
setMsg(e.target.value)
}
return (
<div>
<input type="text" onChange={handleChange} value={msg} />
<List query={query}/>
</div>
)
}
export default App