React 18中新钩子 useDeferredValue 使用

news/2024/7/15 17:31:55 标签: react.js, javascript, 前端

React是一个流行的用于构建用户界面的JavaScript库,它不断发展以为开发人员提供优化性能的工具。

React 18中引入的此类工具之一是useDeferredValue钩子,它旨在通过优先渲染更新来提高应用程序的性能。

useDeferredValue钩子是什么?

useDeferredValue钩子是React性能优化工具集中相对较新的补充。

它在处理异步数据获取(如网络请求或从API加载数据)时特别有用。

useDeferredValue的主要目的是,在立即呈现最重要的部分的同时,推迟对您的应用程序中不太关键的部分的更新。

这可以通过避免用户界面组件呈现延迟而大大提高应用程序的感知性能。

useDeferredValue的基本用法

useDeferredValue钩子的基本用法涉及包装状态值并创建其延迟版本。下面是一个简单的示例:

import { useState, useDeferredValue } from 'react';  

function MyComponent() {
  const [data, setData] = useState([]);
  const deferredData = useDeferredValue(data);   

  // ...
}

在这个例子中,我们有一个状态变量data,它可能会用异步操作填充数据。

通过使用useDeferredValue,我们创建了deferredData,这是data的一个版本,React 会单独优先渲染。

这种分离可确保您的 UI 中的关键部分及时更新,而非关键更新(如渲染列表)可以推迟以降低性能影响。

使用

首次渲染组件时,延迟值将与您传递的值相同。

更新组件时,延迟值将落后于最新值。这意味着 React 会首先使用旧的延迟值重新渲染组件,然后尝试在后台用新延迟值重新渲染它。

下面是一个例子,说明这在什么情况下有用:

想象一下,您有一个搜索栏,当您输入时会获取搜索结果。您开始输入“a”,React 使用加载后备项渲染搜索栏。“a”的搜索结果最终返回,React 使用结果重新渲染搜索栏。

// app.js
import { Suspense, useState } from 'react';
import SearchResults from './SearchResults.js';  

export default function App() {
  const [query, setQuery] = useState('');
  return (
    <>
      <label>  
        Search songs:
        <input value={query} onChange={e => setQuery(e.target.value)} />  
      </label>
      <Suspense fallback={<h2>Loading...</h2>}>
        <SearchResults query={query} />
      </Suspense>
    </>
  );
}
// searchResult.js
import { fetchData } from './data.js';
export default function SearchResults({ query }) {

    if (query === '') {
        return null;
    }
    const songs = use(fetchData(`/search?q=${query}`));

    if (songs.length === 0) {
        return <p>No matches for <i>"{query}"</i></p>;
    }
    return (
        <ul>
            {songs.map(song => (
                <li key={song.id}>  
                    {song.title} ({song.year})
                </li>
            ))}
        </ul>
    );
}  

function use(promise) {
    if (promise.status === 'fulfilled') {
        return promise.value;
    } else if (promise.status === 'rejected') {
        throw promise.reason;
    } else if (promise.status === 'pending') {
        throw promise;
    } else {
        promise.status = 'pending';
        promise.then(
            result => {
                promise.status = 'fulfilled';
                promise.value = result;
            },
            reason => {
                promise.status = 'rejected';
                promise.reason = reason;
            },
        );
        throw promise;
    }
}
// data.js

let cache = new Map();   

export function fetchData(url) {
    if (!cache.has(url)) {
        cache.set(url, getData(url));
    }
    return cache.get(url);
}  

async function getData(url) {
    if (url.startsWith('/search?q=')) {
        return await getSearchResults(url.slice('/search?q='.length));
    } else {
        throw Error('Not implemented');
    }
}

async function getSearchResults(query) {
    // Add a fake delay to make waiting noticeable.
    await new Promise(resolve => {
        setTimeout(resolve, 500);
    });

    const allSongs = [{
        id: 1,
        title: "Bohemian Rhapsody",
        year: 1975
    },
    {
        id: 2,  
        title: "Imagine",
        year: 1971
    },
    {
        id: 3,
        title: "Hotel California",
        year: 1976
    },
    {
        id: 4,
        title: "Stairway to Heaven",  
        year: 1971
    },
    {
        id: 5,
        title: "Let It Be",
        year: 1970
    },
    {
        id: 6,
        title: "Abbey",
        year: 1976
    },
    {
        id: 7,
        title: "A Hard Day's Night",
        year: 2012  
    }];

    const lowerQuery = query.trim().toLowerCase();
    return allSongs.filter(album => {
        const lowerTitle = album.title.toLowerCase();
        return (
            lowerTitle.startsWith(lowerQuery) || 
            lowerTitle.indexOf(' ' + lowerQuery) !== -1  
        )
    });
}

一种常用的替代UI模式涉及推迟更新结果列表并在新结果可用之前持久显示先前结果。

要实现这种方法,可以利用 useDeferredValue 钩子提供查询的延迟版本,因为它在组件层次结构中传播。

// app.js
import { Suspense, useState, useDeferredValue } from 'react';
import SearchResults from './searchResult.js';   

export default function App() {
  const [query, setQuery] = useState('');
  const deferredQuery = useDeferredValue(query);
  return ( 
    <>
      <label>
        Search Songs: 
        <input value={query} onChange={e => setQuery(e.target.value)} />
      </label>
      <Suspense fallback={<h2>Loading...</h2>}>
        <SearchResults query={deferredQuery} />   
      </Suspense>
    </>
  );  
}

现在,您将搜索查询编辑为“ab”。React 会首先使用旧的延迟值重新渲染搜索栏,即“a”的搜索结果。 然后,它会尝试使用新的延迟值重新渲染搜索栏,即“ab”的搜索结果。

这意味着用户不会再看到加载后备,即使“ab”的搜索结果需要很长时间才能返回。

换句话说,延迟值允许您立即渲染UI,即使您正在等待异步数据。 这可以通过避免不必要的加载后备来帮助提高用户体验。

useDeferredValue的好处

  1. 性能提升: 组件或数据的延迟加载和渲染可以导致更快的初始页面加载、降低资源使用和优化性能,从而带来更好的用户体验。

  2. 高效的资源利用: 通过按需加载所需内容,您可以减少不必要的 API 调用、最大限度地减少内存和 CPU 使用,并优化应用程序的资源利用。

  3. 渐进式加载和错误隔离: 延迟值策略支持渐进式加载以实现更高的响应性 UI,并提供更好的错误隔离,确保应用程序的一部分错误不会破坏整个用户体验。


http://www.niftyadmin.cn/n/5319259.html

相关文章

到底什么是商业智能 BI?BI能为企业带来什么, 企业又为啥上BI,全在这里?

随着人工智能、云计算、大数据、互联网、物联网等新一代信息化、数字化技术在各行各业内开始大规模的应用&#xff0c;社会上的数字化、信息化程度不断加深&#xff0c;而数据价值也在这样的刺激下成为了个人、机构、企业乃至国家的重要战略资源&#xff0c;成为了继土地、劳动…

选中图层为什么不能建立3D模型---模大狮模型网

在Photoshop CC 2021(也就是PS6)中&#xff0c;要将选中的图层转换为3D模型&#xff0c;需要满足以下几个条件&#xff1a; 图层类型支持&#xff1a;只有特定类型的图层可以被转换为3D模型。通常&#xff0c;普通的像素图层、矢量图层和形状图层都可以进行转换。但是&#xff…

【Docker】数据管理

&#x1f973;&#x1f973;Welcome 的Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Docker的相关操作吧 目录 &#x1f973;&#x1f973;Welcome 的Huihuis Code World ! !&#x1f973;&#x1f973; 前言 一.数据卷 示例演示 示例剖析…

【cmu15445c++入门】(5)c++中的模板类

一、template模板类 除了模板方法【cmu15445c入门】(4)c中的模板方法 模板也可以用来实现类 二、代码 /*** file templated_classes.cpp* author Abigale Kim (abigalek)* brief Tutorial code for templated classes.*/// Includes std::cout (printing). #include <io…

拼多多根据ID取商品详情原数据 API 实现实时数据获取的完整指南

在电商行业中&#xff0c;商品详情页是用户了解商品信息、进行购买决策的重要页面。为了提高用户体验和促进销售&#xff0c;电商平台通常会提供商品详情的API接口&#xff0c;以便第三方应用能够实时获取商品数据。本文将介绍如何使用拼多多获得的根据ID取商品详情原数据的API…

facebook广告怎么设置受众人群

在设置Facebook广告受众人群时&#xff0c;你可以遵循以下步骤&#xff1a; 打开广告创建工具&#xff0c;点击页面右上角的箭头并选择“创建广告”。选择广告目标&#xff0c;根据想要实现的目标创建广告。例如&#xff0c;想要让更多用户谈论你的主页和帖子&#xff0c;或者…

Google的Ndk-Sample学习笔记之一(hello-jniCallback)

前言: 近段时间因为项目的需求,需要使用JNI,所以下载了Google的Ndk-Sample学习下,准备记录 下来,留给后期自己查看 问题点一:JNI_OnLoad方法必须返回JNI的版本 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {JNIEnv *env;memset(&g_ctx, 0, sizeof(g_…

java使用cxf调用webservice

一、引入cxf <dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-spring-boot-starter-jaxws</artifactId><version>3.2.1</version> </dependency> <dependency><groupId>org.apache.cxf</group…