第37节——useDeferredValue+useTransition

文章介绍了React18中的并发模式,包括如何开启、useTransition和useDeferredValue的作用,以及它们如何帮助优化DOM更新,降低性能消耗,特别关注了在输入框等场景下的应用。同时,文章还对比了useDeferredValue与防抖/节流的区别和startTransition与setTimeout的不同之处。
摘要由CSDN通过智能技术生成

一、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(<App6 />);

三、useDeferredValue和useTransition的作用

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

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

四、useDeferredValue

1、概念

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

const deferredValue = useDeferredValue(value)

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 (
    <div className="container">
      <input onChange={handleChange} />
      {Array(100)
        .fill("a")
        .map((item, index) => (
          <div key={index}>{deferredValue}</div>
        ))}
      <div className="list">
        {Array(20000)
          .fill("a")
          .map((item, index) => (
            <div key={index}>{deferredValue}</div>
          ))}
      </div>
    </div>
  );
}

五、useTransition

1、概念

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

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

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

  const [isPending, startTransition] = useTransition();

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 (
    <div className="container">
      <input onChange={handleChange} />
      {isPending && "等待中"}
      {Array(100)
        .fill("a")
        .map((item, index) => (
          <div key={index}>{value}</div>
        ))}
      <div className="list">
        {Array(20000)
          .fill("a")
          .map((item) => (
            <div key={index}>{value}</div>
          ))}
      </div>
    </div>
  );
}

六、使用场景

当使用大屏幕的时候,这里的大屏幕并不是单纯指的是尺寸,而是一种数据量大,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

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 [
    <p>{"我被触发了" + count + "次"}</p>,
    <ul>
      {list.map((item, index) => (
        <li key={index}>
          Hello:{item.name} value:{item.value}
        </li>
      ))}
    </ul>,
  ];
};

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 (
    <div className="App">
      <input value={text} onChange={handleChange} />
      <div>DeferredValue</div>
      <List text={deferredText} />
      <div>防抖</div>
      <List text={debouncedValue} />
    </div>
  );
}

九、对比 setTimeout

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值