当前位置: 首页 > news >正文

React18 Transition特性详解

Transition 核心概念:Transition是一种标记非紧急任务更新的机制,它允许React在用户交互(如输入)期间保持界面的响应,同时准备后台更新

主要特点:

  • 区分优先级:可以将更新分为紧急非紧急任务
  • 可中断渲染:Transition更新可以被更紧急的交互打断
  • 自动降级:在不支持并发环境中自动回退到同步渲染

场景:
在Input中输入搜索内容,过滤列表,由于数据量比较大10万条数据导致页面卡死
那如何处理此瓶颈:10万条数据分页还是利用虚拟滚动实现假性分页。
如果把同步更新任务变成异步更新任务是不是就可以解决问题。Transition就可以处理多个并发任务

Input表单的并发任务分别为:

  • 更新Input的内容,同时会触发更新任务(高优先级的任务)
  • Input内容改变,过滤列表,重新渲染也是一个任务(低优先级任务)

这里的任务可以分为紧急优先级任务和非紧急任务

紧急任务就是当用户改变Input框的内容时候要立马能够看到更新后的内容,不然就会有卡顿、延迟。会有一种极差的视觉体验
非紧急任务是当input输入内容后,过滤列表并重新渲染列表,这个过程如果有延迟,用户也是可以接受的

什么是紧急任务:直接影响用户即时交互的界面更新,在本例中,输入框value的更新、输入框的光标位置、焦点状态等
什么是非紧急任务:可以稍后处理的计算密集型或网络请求
为什么紧急:每次用户操作后需要立即看到输入后的反馈,否则顿感卡顿,如果延迟处理,会导致输入内容与显示不一致,糟糕的用户体验
为什么非紧急:用户能够容忍短暂的结果延迟,如果与输入框竞争资源,反而会导致输入卡顿

Transition基本用法:

import { startTransition } from 'react';// 在事件处理中
function handleInputChange(e) {const value = e.target.value;// 紧急更新:立即更新输入框setInputValue(value);// 非紧急更新:标记为TransitionstartTransition(() => {setSearchQuery(value); // 可能触发大量计算的更新});
}

使用 useTransition Hook

import { useTransition } from 'react';function SearchBox() {const [isPending, startTransition] = useTransition();const handleChange = (e) => {const value = e.target.value;setInputValue(value);startTransition(() => {setSearchQuery(value);});};return (<div><input onChange={handleChange} />{isPending && <Spinner />} {/* 显示过渡状态 */}</div>);
}

上述案例完整代码:

import { useState, useTransition } from 'react';function SearchComponent() {const [inputValue, setInputValue] = useState('');const [searchResults, setSearchResults] = useState([]);const [isPending, startTransition] = useTransition();// 实际项目中实现的搜索函数async function performHeavySearch(keyword) {const response = await fetch(`/api/search?q=${keyword}`);const data = await response.json();return data.items; // 根据实际API结构调整}const handleChange = async (e) => {const value = e.target.value;setInputValue(value);startTransition(async () => {const results = await performHeavySearch(value);setSearchResults(results);});};return (<div><input value={inputValue} onChange={handleChange} />{isPending ? (<div>Searching...</div>) : (<ul>{searchResults.map(item => (<li key={item.id}>{item.name}</li>))}</ul>)}</div>);
}

典型案例:

  • 搜索输入:输入时保持输入框响应,搜索结果稍后显示
  • 标签页切换:点击切换标签时立即显示激活状态,内容稍后加载
  • 大数据渲染:优先渲染可见部分,其他内容渐进加载

与Suspense的结合使用:Transition 可以与 Suspense 完美配合,实现流畅的异步加载体验:

import { Suspense, useTransition } from 'react';function App() {const [resource, setResource] = useState(initialResource);const [isPending, startTransition] = useTransition();function fetchNewData() {startTransition(() => {setResource(fetchData()); // 返回一个Suspense兼容的资源});}return (<div><button onClick={fetchNewData}disabled={isPending}>{isPending ? 'Loading...' : 'Load Data'}</button><Suspense fallback={<Spinner />}> {/* Spinner 显示过渡状态 */}<DataDisplay resource={resource} /></Suspense></div>);
}

React中Suspense和核心功能:

1、作用:

  • 用在子组件(懒加载或异步数据请求)完成加载前显示一个后备方案(fallback UI),例如加载动画或者占位符
  • 支持代码分割(通过React.lazy)和异步数据加载(需支持Suspense的库,如react query或relay)

2、关键特性:

  • 代码分割:与react.lazy结合,实现组件按需加载
  • 数据加载:需依赖Suspense库,原生react不支持异步数据Suspense
  • 嵌套使用:允许逐步加载内容,优化用户体验

3、示例:

<Suspense fallback={<Loading />}><LazyComponent />  // 通过 React.lazy 加载
</Suspense>

与vue中的Suspense

1、作用

  • 处理异步组件或异步setup函数加载状态,显示后备内容
  • 支持任意异步逻辑(如数据请求或动态导入组件),不限于组件级懒加载

2、关键特性

  • 插槽设计:通过#default和#fallback插槽管理内容
  • 事件监听:提供pending、resolve等事件、便于控制加载状态
  • 嵌套支持:子组件的异步依赖会触发父级Suspense的fallback

3、示例

<Suspense><template #default><AsyncComponent />  // 异步组件或含 async setup 的组件</template><template #fallback><Loading /></template>
</Suspense>

主要区别:

特性React SuspenseVue Suspense
支持范围主要针对组件懒加载、异步数据请求、数据需要第三方支持支持任意异步逻辑(组件、数据等)
API 设计通过fallback prop定义占位内容使用插槽(#default 和 #fallback
嵌套行为内部Suspense优先处理父级的Suspense等子异步依赖完成再处理
事件监听无内置事件通过pending、resolve、fallback等事件

vue3中Suspense中事件用法

<template><Suspense @pending="onPending"@resolve="onResolve"@fallback="onFallback"><template #default><AsyncComponent /></template><template #fallback><div>Loading...</div></template></Suspense>
</template><script setup>
import { defineAsyncComponent } from 'vue';const AsyncComponent = defineAsyncComponent(() => import('./AsyncComponent.vue')
);function onPending() {console.log('开始异步加载');// 可以在这里显示全局加载状态// 发送分析事件analytics.track('DashboardLoadStart');
}function onResolve() {console.log('异步加载完成');// 可以在这里隐藏全局加载状态// 发送性能数据analytics.track('DashboardLoaded', { duration: loadTime });
}function onFallback() {console.log('Fallback内容被展示');// 可以记录fallback显示时间等
}
</script>

备注:这里面可以用作性能监控,当开始的时候发送事件分析,当结束时候获得性能数据

代码分割详解:

代码分割是前端性能优化中的重要技术。
代码分割是将整个应用分割成多个小块,然后按需加载,而不是一次性加载所有代码,这可以:

  • 显著减少初始加载时间
  • 降低首屏资源体积
  • 通过应用交互响应速度

传统代码分割问题:

// 传统动态导入方式
import("./MyComponent.js").then(module => {// 组件加载完成后才能使用
});
  • 需要手动处理加载状态
  • 容易导致布局跳动或空白
  • 代码组织不够直观

Suspense如何分割代码

React:

const MyComponent = React.lazy(() => import('./MyComponent'));function App() {return (<Suspense fallback={<div>Loading...</div>}><MyComponent />  {/* 被代码分割的组件 */}</Suspense>);
}

Vue3:

<script setup>
const AsyncComp = defineAsyncComponent(() => import('./MyComponent.vue')
)
</script><template><Suspense><template #default><AsyncComp /></template><template #fallback><div>Loading...</div></template></Suspense>
</template>
  • 动态导入组件
  • 导入过程中,Suspense显示fallback内容
  • 加载完成后,替换为实际组件

技术实现细节:
Webpack的代码分割:当使用import()语法时,打包工具会自动:

  • 将目标分割成一个独立的chunk文件
  • 生成运行时候加载逻辑
  • 在需要时通过 JSONP动态获取

Suspense的协调机制:

  • React/Vue会自动追踪异步组件加载状态
  • 在模块加载期间暂停渲染
  • 加载完成后重新触发渲染

为什么需要Suspense

无Suspense有Suspense
需要手动维护loading统一处理loading
多个异步加载时状态复杂支持嵌套异步依赖
错误处理困难与错误边界(Error Boundaries)天然集成

性能优化技巧:

预加载策略:

// 鼠标悬停时预加载
function onLinkHover() {import('./ComponentToPrefetch');
}

命名chunks:

const Component = lazy(() => import(/* webpackChunkName: "specific-name" */ './Component'
));

Suspense嵌套:

<Suspense fallback={<AppLoader />}><Layout><Suspense fallback={<SidebarLoader />}><Sidebar /></Suspense></Layout>
</Suspense>
http://www.dtcms.com/a/325257.html

相关文章:

  • ARM汇编
  • Apache IoTDB 全场景部署:跨「端-边-云」的时序数据库 DB+AI 实战
  • 一维码+二维码+字符识别
  • 【数据结构】深入理解顺序表与通讯录项目的实现
  • 第十六届蓝桥杯大赛青少组 C++ 省赛真题解析(2025年8月10日)
  • 动态创建可变对象:Python类工厂函数深度解析
  • 云原生环境 Prometheus 企业级监控实战
  • 本地文件夹与 GitHub 远程仓库绑定并进行日常操作的完整命令流程
  • 时序数据库选型指南:Apache IoTDB为何成为工业物联网首选?
  • 精读:《DEEP OC-SORT: MULTI-PEDESTRIAN TRACKING BY ADAPTIVE RE-IDENTIFICATION》
  • 网安-安全加固
  • 安装jieba时遇到ModuleNotFoundError: No module named ‘distutils’
  • 2025世界机器人大会,多形态机器人开启商业化落地浪潮
  • stm32内存分析和RTOS任务切换分析
  • 第5节 大模型分布式推理通信优化与硬件协同
  • 高并发场景下分布式ID生成方案对比与实践指南
  • Web安全自动化测试实战指南:Python与Selenium在验证码处理中的应用
  • Redis知识点笔记
  • buildroot编译qt 5.9.8 arm64版本踩坑
  • 【车联网kafka】Kafka核心架构与实战经验(第三篇)
  • Java Web项目后台管理系统之内容管理仿写:内容、搜索、页码加载
  • 【Kafka系列】第三篇| 在哪些场景下会选择使用 Kafka?
  • 虚幻GAS底层原理解剖十 (网络)
  • 33-Hive SQL DML语法之查询数据-2
  • word的正则替换
  • 面试题-----微服务业务
  • 覆盖近 1.5 万个物种,谷歌 DeepMind 发布 Perch 2.0,刷新生物声学分类检测 SOTA
  • 深度学习与遥感入门(五)|GAT 构图消融 + 分块全图预测:更稳更快的高光谱图分类(PyTorch Geometric 实战)
  • Vue 中的 Class 与 Style 绑定详解1
  • 记录一下通过STC的ISP软件修改stc32的EEPROM值大小