React 第二十一节 useDeferredValue 开发中用法注意事项

发布于:2025-02-10 ⋅ 阅读:(62) ⋅ 点赞:(0)

1、概述

useDeferredValue 是用于延迟渲染视图UI组件的,可以帮助我们管理视图渲染过程中的状态,并提高程序运行的性能;

2、用法

const deferredVal = useDeferredValue(params)

params: 是我们需要延迟的数据;可以是任何类型的数据,可以是基础类型,也可以是引用类型;
deferredVal:返回的延迟值

初始化渲染时候:useDeferredValue 返回的延迟值与 我们提供的值是一样的,
组件更新时候:React 先使用旧值进行 渲染,并且在后台使用 延迟值进行另一个线程渲染;

3、用途

用于复杂的数据计算或者网络请求数据响应比较缓慢的场景中;这样可以避免频繁的更新状态视图;
比如:长列表的搜索框,当用户每次输入关键字时候,我们都需要发起请求,同时更新状态,通过状态驱动视图重新渲染,这样会导致更新过于频繁,而影响渲染进程性能;

模拟10000条数据渲染;

// 父组件
import {Suspense, useState, useDeferredValue } from 'react'
import List from './List'
export default function MyDeferredValue() {
    const [params, setParams] = useState('')
    const deferredVal = useDeferredValue(params)
    const handleChangeParams = (e) => {
        setParams(e.target.value)
    }
  return (
    <div>
        <label>
            搜索:
            <input type="text" value={deferredVal} onChange={handleChangeParams} />
        </label>
      <p>deferredVal--{deferredVal}</p>
      <p>params--{params}</p>
      <Suspense fallback={<h2>loading...</h2>}>
        <List params={params}></List>
      </Suspense>
    </div>
  )
}

子组件监听 传入的 关键字params 进行数据过滤,当数据量大时候,发现params已最新值,而deferredVal 依旧是原值,此时视图依然保持原样,频繁输入时候,列表只会渲染最后一次输入的关键字;

import { useState, useEffect } from 'react'

export default function List({params}) {
    console.log('=params==', params)
    let data = []
    const [dataArr, setDataArr] = useState([])
    for (let i = 0; i < 10000; i++) {
      data.push({
        title: `名称${i+1}`,
        id: i,
        content: String(Math.random() * 100 )
      })
    }
    useEffect(() => {
        return () => {
            let newData = data.filter(itm => (itm.title.indexOf(params) > -1 || itm.content.indexOf(params) > -1))
            setDataArr([...newData])
        }
    }, [params])
    
  return (
    <div>
      <ul>
        {dataArr.map((item) => (
          <li key={item.id}>{item.title}-{item.content}</li>
        ))}
      </ul>
    </div>
  )
}

4、注意事项:

4.1、若我们需要延迟的数据是引用类型,并且每次组件更新时候都会创建一个新对象,并将新对象立即传递给 useDeferredValue,那么会因为引用对象的指向不一样,而导致视图每次都会重新渲染,这样就会增加不必要的渲染次数;
4.2、useDeferredValue 接收的值,每次都会使用Object.is() 进行对比,如果不一样,则会中断后台的视图渲染,进而使用新的延迟值 deferredVal 进行渲染;
4.3、useDeferredValue 本身不会阻止额外网络的请求;
4.4、useDeferredValue 本身并不会引起固定的延迟;在React 中只要当前渲染进程完成,React则会使用新的延迟值进行处理后台的重新渲染,
4.5、useDeferredValue 使用延迟值在后台完成的渲染,提交到前台屏幕视图时,不会触发Effect;而当后台渲染被中断时候,Effect 会咋子数据加载后后UI视图渲染后进行;
4.6、useDeferredValue 由于无法预知下次更新时间,可能是在很长的时间才能更新数据,这时可能组件已经卸载,那么就会导致 内存溢出 情况;
useDeferredValue 还提供了取消更新的函数;

   const [params, setParams, cancelUpdate] = useDeferredValue(initvalue)
   Effect(() => {
       return () => {
           // 取消延时更新函数
           cancelUpdate()
       }
   }, [])
   ```

4.7、useDeferredValue 可以传入配置对象;

     const [params, setParams] = useDeferredValue(initValue, {
     timeoutMs: 500, // 延迟更新时间,单位毫秒
     maximumTimeMs: 2000, // 最长延迟更新时间,单位毫秒
     equalityFn: (a, b) => a.id === b.id, // 状态相等性比较函数
 ```



注:上述内容如果遗落错误,欢迎批评指正,大龄程序员正在寻找新的出路

网站公告

今日签到

点亮在社区的每一天
去签到