开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 28 天,点击查看活动详情
useDeferredValue
useDeferredValue 接受一个值,并返回该值的新副本,该副本将推迟到更紧急地更新之后。如果当前渲染是一个紧急更新的结果,比如用户输入,React 将返回之前的值,然后在紧急渲染完成后渲染新的值。
首先有一个父组件,这个父组件不干什么,就是有一个state,然后改变这个state,这个state会传递给list这个子组件
export default function DeferredValue() {
const [text, setText] = useState('骚帮')
const handleChange = (e) => {
setText(e.target.value)
}
return (
<div className="App">
<input value={text} onChange={handleChange} />
<List text={text} />
</div>
)
}
子组件里是这个情况,自身有两个state,但是这两个state会根据props.text变动而变动,变动是都会变动的,但是有一个谁先变动谁变动说法,毕竟人类的进步的一大特征就是有文化的先上。这里也是分个优先级,并不是先来后到那么简单
特点如下,当大家都是普通的依赖时,就是传统的props.text,前面的effect总是先执行 但是当有使用useDeferredValue包裹的依赖时,依赖这个值的effect优先级就比较低,总是最后执行,当然如果都是依赖这种数据的effect,顺序也是从上到下。
const List = (props) => {
const deferredText = useDeferredValue(props.text)
const [list, setList] = useState([])
const [list2, setList2] = useState([])
useEffect(() => {
console.log('deferredText')
setList(
new Array(10).fill(null).map(() => {
return { name: deferredText, value: Math.random() }
})
)
}, [deferredText])
useEffect(() => {
console.log('text')
setList2(
new Array(10).fill(null).map(() => {
return { name: deferredText, value: Math.random() }
})
)
}, [props.text])
return (
<>
<ul>
{list.map((item) => (
<li key={item.value}>
Hello:{item.name} value:{item.value}
</li>
))}
</ul>
<ul>
{list2.map((item) => (
<li key={item.value}>
Hello:{item.name} value:{item.value}
</li>
))}
</ul>
</>
)
}
const deferredText = useDeferredValue(props.text)
const [list, setList] = useState([])
const [list2, setList2] = useState([])
useEffect(() => {
console.log('deferredText')
setList(
new Array(10).fill(null).map(() => {
return { name: deferredText, value: Math.random() }
})
)
}, [deferredText])
useEffect(() => {
console.log('text2')
setList(
new Array(10).fill(null).map(() => {
return { name: props.text, value: Math.random() }
})
)
}, [props.text])
useEffect(() => {
console.log('text')
setList2(
new Array(10).fill(null).map(() => {
return { name: props.text, value: Math.random() }
})
)
}, [props.text])
useEffect(() => {
console.log('deferredText2')
setList2(
new Array(10).fill(null).map(() => {
return { name: deferredText, value: Math.random() }
})
)
}, [deferredText])
上面effect的执行顺序也是这个道理,相同优先级的顺序从上到下,useDeferredValue的优先级比普通的数据的副作用执行时机优先级低。
useTransition
useTransiton和useDeferredValue这两个作用感觉一模一样
还是上面的例子,在父组件稍微改动一下,将setText这个过程的优先使用useTransition这个钩子控制一下。那么这个text就相当于被useDeferredValue了一下一样。依赖它更新的优先级就是最低级别的了,所以就算你再使用useDeferredValue包裹一下,他的优先级也不会再低了。
export default function DeferredValue() {
const [text, setText] = useState('骚帮')
const [isPedding, startTransition] = useTransition()
const handleChange = (e) => {
startTransition(() => setText(e.target.value))
}
return (
<div className="App">
<input value={text} onChange={handleChange} />
<div>{text}</div>
{isPedding ? "loading...." : <List text={text} />}
</div>
)
}
所以这时子组件的useEfect的更新顺序你猜的到吗? deferredText > text2 > text > deferredText2 就是按照副作用书写的顺序来执行了。
useDeferredValue 和 useTransition 区别
这两个作用几乎无区别,但是适合不同场景而已,当一个父组件的状态不一定是低优先级的时候,我们定然不可以直接使用useTransition控制更新过程,可以在某个期望这个更新优先级低的组件里使用useDeferredValue将这个props转成低优先级的。 当这个状态的优先级更新确定是低的时候,就可以使用useTransition包裹一下砸