关于前端:React-18中的useTransition和useDeferredValue使用

React18 引入了一个要害概念 并发性(Concurrency)。 并发则波及到多个更新操作的同时执行,这能够说是React18中最重要的性能。
除了并发,React18 新增了两个hook ,也就是useTransitionuseDeferredValue。它们的作用都是升高更新操作的优先级,但问题是,何时应该应用它们?

并发(Concurrent)

在实现”并发”之前,渲染是同步的(所谓的同步,就是指如果react的某个组件执行工夫长,它无奈中断,会始终执行,直到组件齐全渲染到DOM中。在这个过程中,因为Javascript是单线程的,因而渲染工作会占满JavaScript线程,阻塞浏览器的主线程,从而导致用户无奈进行交互操作)。

然而,有了并发渲染(并发指的就是通过time slice将工作拆分为多个,而后react依据优先级来实现调度策略,将低优先级的工作先挂起,将高优先级的任务分配到浏览器主线程的一帧的闲暇工夫中去执行,如果浏览器在以后一帧中还有残余的闲暇工夫,那么React就会利用闲暇工夫来执行剩下的低优先级的工作),react的渲染和更新能够被中断和复原。那么如果在执行某个组件更新过程中又有了新的更新申请达到。比方咱们上面的input输出事件,那么React就会创立一个新的更新版本。这种状况下,在某个时间段内可能会同时存在多个更新版本

为了优化上述问题,React 18 提供了新的 Hook 函数 useTransition,它能够将多个版本的更新打包到一起,在将来的某一帧闲暇工夫内执行,从而优化利用的性能和响应工夫。而useDeferredValue 的作用是将某个值的更新推延到将来的某个工夫片内执行,从而防止不必要的反复渲染和性能开销。

没有应用任何优化伎俩,同步更新

假如咱们有一个蕴含从0到19,999数字的数组。这些数字在用户界面上显示为一个列表。该用户界面还有一个文本框,容许咱们过滤这些数字。例如,我能够通过在文本框中输出数字99来过滤掉以99结尾的数字。

import { useState, useTransition } from "react";

const numbers = [...new Array(20000).keys()];

export default function App() {
    const [query, setQuery] = useState("");

    const handleChange = (e) => {
        setQuery(e.target.value);
    };

    return (
        <div>
            <input type="number" onChange={handleChange}/>
            <div>
                {
                    numbers.map((i, index) => (
                        query
                            ? i.toString().startsWith(query)
                            && <p key={index}>{i}</p>
                            : <p key={index}>{i}</p>
                    ))
                }
            </div>
        </div>
    );
}

因为数组中有20,000个元素,过滤将是一个有点耗时的过程。当咱们试图在文本框中输出一个数字时,咱们能够察看到这一点。输出的数值呈现在文本框中会有一个滞后,因为每一个按键之后的渲染都会破费一些工夫。

useTransition

接下来咱们应用useTransition来批改一下下面的代码

function App() {
    const [query, setQuery] = useState("");
    const [isPending, startTransition] = useTransition();

    const handleChange = (e) => {
        startTransition(() => {
            setQuery(e.target.value);
        });
    };

    const list = useMemo(() => (
        numbers.map((i, index) => (
            query
                ? i.toString().startsWith(query)
                && <p key={index}>{i}</p>
                : <p key={index}>{i}</p>
        ))
    ), [query]);

    return (
        <div>
            <input type="number" onChange={handleChange} />
            <div>
                {
                    isPending
                        ? "Loading..."
                        : list
                }
            </div>
        </div>
    );
}

从下面能够看到useTransation返回一个蕴含两个子项的数组。

isPending: 通知你目前是否有一些更新操作任然在期待中(尚未被React执行,并以较低的优先级解决)
startTransition: React会以一个较低的优先级调度被它包装的更新操作

这样,就确保了用户和输入框的交互操作放弃晦涩。而后再通过isPending来判断是否能够更新UI。

useDeferredValue

useDeferredValue的作用和useTransition统一,都是用于在不阻塞UI的状况下更新状态。然而应用场景不同。

useTransition是让你可能齐全管制哪个更新操作应该以一个比拟低的优先级被调度。然而,在某些状况下,可能无法访问理论的更新操作(例如,状态是从父组件上传下来的)。这时候,就能够应用useDeferredValue来代替。

用React 团队成员Dan的话说useDeferredValue次要是:

useful when the value comes “from above” and you don’t actually have control over the corresponding setState call.

它的意思就是: 当值来自 “下层”,而你实际上不能管制相应的setState调用时,这个办法很有用。

这就比拟符合咱们下面所举例子的场景。

那咱们就须要将下面的例子改成如下:

import { useState, useMemo, useDeferredValue } from "react";

const numbers = [...new Array(200000).keys()];

export default function App() {
    const [query, setQuery] = useState("");

    const handleChange = (e) => {
        setQuery(e.target.value);
    };

    return (
        <div>
            <input type="number" onChange={handleChange} value={query} />
            <List query={query} />
        </div>
    );
}

function List(props) {
    const { query } = props;
    const defQuery = useDeferredValue(query);

    const list = useMemo(() => (
        numbers.map((i, index) => (
            defQuery
                ? i.toString().startsWith(defQuery)
                && <p key={index}>{i}</p>
                : <p key={index}>{i}</p>
        ))
    ), [defQuery]);

    return (
        <div>
            {list}
        </div>
    );
}

总结

如上所述,useTransition间接管制更新状态的代码,而useDeferredValue管制一个受状态变动影响的值。它们做的是同样的事,帮忙进步用户体验(UX),不应该同时应用这两者。

相同,如果你能够拜访更新操作,并且有一些更新操作应该以较低的优先级解决,就应用useTransition。如果你没有这种权限,就应用useDeferredValue

参考

useTransition and useDeferredValue in React 18
UseTransition() Vs UseDeferredValue() In React 18

【腾讯云】轻量 2核2G4M,首年65元

阿里云限时活动-云数据库 RDS MySQL  1核2G配置 1.88/月 速抢

本文由乐趣区整理发布,转载请注明出处,谢谢。

您可能还喜欢...

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据