• 第37节——useDeferredValue+useTransition


    一、Concurrent React

    一种新的幕后机制,使 React 能够同时准备多个版本的 UI。您可以将并发视为一个实现细节——它的价值在于它的特性

    并发涉及同时执行多个状态更新,这可以说是 React 18 中最重要的特性。除了并发之外,React 18 还引入了两个新的钩子,称为 useTransition() 和 useDeferredValue() 钩子。

    它们都有助于降低状态更新的优先级

    二、开启并发模式

    concurrent Mode 渲染并发模式在react 18 中才可以使用,要先开启并发模式,也就是需要通过 createRoot 创建 Root 。(脚手架会自动创建)

    const root = ReactDOM.createRoot(document.getElementById("root"));
    root.render();
    
    • 1
    • 2

    三、useDeferredValue和useTransition的作用

    useDeferredValue 和useTransition这两个钩子可以让我们延迟渲染不紧急的部分,类似于防抖但没有固定的延迟时间,延迟的渲染会在紧急的部分先出现在浏览器屏幕以后才开始,并且可中断,不会阻塞用户输入。

    简单理解就是如果说某些渲染比较消耗性能,比如存在实时计算和反馈,我们可以使用这个Hook降低其计算的优先级,使得避免整个应用变得卡顿。较多的场景可能就在于用户反馈输入上。比如百度的输入框,用户在输入的时候,页面会发生变化,但是输入框输入并不卡顿

    四、useDeferredValue

    1、概念

    接收一个要变化的参数,该参数会被打上标记低优先级更新, 返回一个延迟响应的状态。我们在使用的时候,想要对useState里面的数据延迟更新,则可以把输入传到useDeferredValue中,然后使用它的返回值

    const deferredValue = useDeferredValue(value)
    
    • 1

    2、实际例子

    当用户输入的时候,大量的dom的更新会造成输入框的卡顿,使用useDeferredValue来优化一下

    import { useTransition } from "react";
    import { useState, useDeferredValue } from "react";
    
    export default function App() {
      const [value, setValue] = useState("");
    
      
      const deferredValue  = useDeferredValue(value)
      
    
      const handleChange = (e) => {
        setValue(e.target.value);
      };
    
      return (
        
    {Array(100) .fill("a") .map((item, index) => (
    {deferredValue}
    ))}
    {Array(20000) .fill("a") .map((item, index) => (
    {deferredValue}
    ))}
    ); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    五、useTransition

    1、概念

    useTransition() 告诉 React 一些状态更新具有较低的优先级。当我们调用 useTransition() 时,我们得到一个包含两个元素的数组:

    isPending 布尔值,它指示低优先级状态更新是否仍处于挂起状态,

    startTransition() 函数, 接收一个回调函数,优先级较低的任务可以放到函数里面

      const [isPending, startTransition] = useTransition();
    
    • 1

    2、实际例子

    当用户输入的时候,大量的dom的更新会造成输入框的卡顿,使用useTransition来优化一下

    import { useState, useTransition } from "react";
    
    export default function App() {
      const [value, setValue] = useState("");
    
    
      const [isPending, startTransition] = useTransition();
    
    
    
      const handleChange = (e) => {
        startTransition(() => {
          setValue(e.target.value);
        });
      };
    
      return (
        
    {isPending && "等待中"} {Array(100) .fill("a") .map((item, index) => (
    {value}
    ))}
    {Array(20000) .fill("a") .map((item) => (
    {value}
    ))}
    ); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    六、使用场景

    当使用大屏幕的时候,这里的大屏幕并不是单纯指的是尺寸,而是一种数据量大,DOM 元素节点多的场景

    七、useDeferredValue vs useTransition

    1、相同点

    useDeferredValue 本质上和内部实现与 useTransition 一样都是把任务标记成了过渡更新任务。

    2、不同点

    useTransition 是把 startTransition 内部的更新任务变成了过渡任务transtion,而 useDeferredValue 是把原值通过过渡任务得到新的值,这个值作为延时状态。 也就是说一个是处理一段逻辑,另一个是生产一个新的状态。

    useDeferredValue 还有一个不同点就是这个任务,本质上在 useEffect 内部执行,而 useEffect 内部逻辑是异步执行的 ,所以它一定程度上更滞后于 useTransition。可以理解成useDeferredValue = useEffect + transtion

    八、对比防抖

    1、节流防抖本质是 setTimeout ,只不过控制了执行的频率,原理就是让 render 次数减少了。而 transitions 和它相比,并没有减少渲染的次数。

    2、节流和防抖需要有效掌握延迟时间,如果时间过长,那么给人一种渲染滞后的感觉,如果时间过短,那么就类似于 setTimeout(fn,0) 还会造成前面的问题。而 startTransition 就不需要考虑这么多

    1、下载ahooks

    npm install ahooks
    
    • 1

    2、两者对比

    import React, { useState, useEffect, useDeferredValue } from "react";
    import { useDebounce } from "ahooks";
    const List = (props) => {
      const [list, setList] = useState([]);
      const [count, setCount] = useState(0);
      useEffect(() => {
        setCount((count) => count + 1);
        setList([
          { name: props.text },
          { name: props.text },
          { name: props.text },
          { name: props.text },
        ]);
      }, [props.text]);
      return [
        

    {"我被触发了" + count + "次"}

    ,
      {list.map((item, index) => (
    • Hello:{item.name} value:{item.value}
    • ))}
    , ]; }; export default function App() { const [text, setText] = useState(""); const deferredText = useDeferredValue(text); /** * 第一个参数要节流的state * 也就是放useState里面拿到值 * 当这个值频繁变化的时候,只会触发最后一次 * 第二个参数是一个对象 * 里面可以传一个wait 等待时间 */ console.log(text); const debouncedValue = useDebounce(text, { wait: 1000 }); const handleChange = (e) => { setText(e.target.value); }; return (
    DeferredValue
    防抖
    ); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    九、对比 setTimeout

    1、startTransition 的处理逻辑和 setTimeout 有一个很重要的区别,setTimeout 是异步延时执行,而 startTransition 的回调函数是同步执行的。在 startTransition 之中任何更新,都会被react打上一个标记,React 在更新的时候会通过这个标记来判断是否完成本次更新。所以startTransition 可以理解成比 setTimeout 更早的更新。

    2、在 conCurrent mode 下,startTransition 是可以中断渲染的 ,所以它不会让页面卡顿,React 让这些任务,在浏览器空闲时间执行,所以上述输入 input 内容时,startTransition 会优先处理 input 值的更新,而之后才是列表的渲染。setTimeout则是只要到时间,就会执行。

  • 相关阅读:
    力扣946:验证栈序列
    mysql第三次作业
    Java创建对象的两种情况(显式创建和隐含创建)
    微信小程序如何利用接口返回经纬计算实际位置并且进行导航功能【下】
    libopenssl 实现私钥加密公钥解密
    HTTP 参数污染 (HPP) 和 HTTP 参数碎片 (HPF)
    为什么ASO很重要?
    Apache Doris (四十六): Doris数据更新与删除 - 批量删除
    基于web的学校二手书城系统/二手书交易系统
    Flutter 7 个开源项目推荐 01
  • 原文地址:https://blog.csdn.net/weixin_57017198/article/details/133241272