react教程,如何使用useDeferredValue延迟state更新界面?
发布于 作者:苏南大叔 来源:程序如此灵动~ 我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...
在react
项目中,大家都知道state
的变化,一般会引起界面的更新。一些界面的更新会比较耗时,并且相对而言,这些耗时界面的更新也并不是那么重要。那么这种情况下,就可以用到useDeferredValue
来延迟对应状态值的更新,进而改善界面的更新效果。这个也是属于react
项目优化的部分,不使用useDeferredValue
的话,也没有啥大问题,就是可能会有些界面卡顿而已。
苏南大叔的程序如此灵动博客,记录苏南大叔和计算机代码的故事。测试环境:create-react-app@5.0.1
,react@18.2.0
,react-dom@18.2.0
,node@16.14.2
。
方案一【useDeferredValue】
本文的场景下,有两个菜单,每个菜单下面有“5000”个子菜单。【个数这么多的目的,就是要造出渲染的延迟效果】。场景模拟的就是点击切换菜单的效果。
import React from 'react';
const menuConfig = {
苏南: Array(5000).fill('1').map((item, index) => "menu-" + item + "-" + index),
大叔: Array(5000).fill('2').map((item, index) => "menu-" + item + "-" + index),
}
function DeferValueDemo() {
const [activeMenu, setActiveMenu] = React.useState('苏南');
const handleChangeTab = (activeMenuItem) => {
setActiveMenu(activeMenuItem) // 立即更新
}
const activeMenuDefer = React.useDeferredValue(activeMenu); // 状态延时更新
const renderData = menuConfig[activeMenuDefer]; // 使用滞后状态
// const renderData = menuConfig[activeMenu]; // 不使用滞后状态
return <div>
<div className='tab' >
{Object.keys(menuConfig).map((item, index) =>
<span key={index} className={(activeMenu === item) ? 'activeMenu' : ""} onClick={() => handleChangeTab(item)}>{item}</span>
)}
</div>
<ul className='content'>
{ renderData.map(item => <li key={item}>{item}</li>) }
</ul>
</div>
}
export default function App() {
return (
<>
<style>{`span.activeMenu{color:red;}`}</style>
<DeferValueDemo />
</>
)
}
在本文中,为了准确甄别出useDeferredValue
的效果,可以观察下面两者发生的先后顺序:父菜单的颜色变化、子菜单的内容变化。
情况一:使用延迟状态版本
核心代码如下:
const [activeMenu, setActiveMenu] = React.useState('苏南');
const activeMenuDefer = React.useDeferredValue(activeMenu);
activeMenu
就是平常概念上的state
值,它的变化会立刻引发其他相关界面的变化。activeMenuDefer
就是activeMenu
的延迟版本,它的变化所引起的界面变化的优先级最低。
在使用延迟状态的情况下,效果是父菜单先变红色,然后延迟1秒左右子菜单内容才变化(主要是子菜单太多了)。
情况二:不使用延迟状态版本
如果不想使用延迟的状态版本,那么可以这样写:
const renderData = menuConfig[activeMenu];
在不使用延迟状态的情况下,效果是:延迟1秒左右子菜单内容才变化,然后父菜单先红色,就是说界面被卡死了。
方案二【useTransition】
实际上也可以使用useTransition()
来解决本文的需求,代码如下:
import React from 'react';
const menuConfig = {
苏南: Array(5000).fill('1').map((item, index) => "menu-" + item + "-" + index),
大叔: Array(5000).fill('2').map((item, index) => "menu-" + item + "-" + index),
}
function DeferValueDemo() {
const [activeMenu, setActiveMenu] = React.useState('苏南');
const [renderData, setRenderData] = React.useState(menuConfig[activeMenu])
const [isPending, startTransition] = React.useTransition();
const handleChangeTab = (activeMenu) => {
setActiveMenu(activeMenu) // 立即更新
startTransition(() => { // 延迟更新
setRenderData(menuConfig[activeMenu])
})
}
return <div>
<div className='tab' >
{Object.keys(menuConfig).map((item, index) =>
<span key={index} className={(activeMenu === item) ? 'activeMenu' : ""} onClick={() => handleChangeTab(item)}>{item}</span>
)}
</div>
<ul className='content'>
{isPending && <div> loading... </div>}
{renderData.map(item => <li key={item}>{item}</li>)}
</ul>
</div>
}
export default function App() {
return (
<>
<style>{`span.activeMenu{color:red;}`}</style>
<DeferValueDemo />
</>
)
}
方案对比
两种方案最终的效果,都是差不多的。但是,原理上来说,还是有所区别的。
名称 | 区别 |
---|---|
useDeferredValue() | 延迟的是状态值 |
useTransition() | 延迟的是状态组装界面的过程 |
参考文字:
结束语
更多react
相关经验文字,请点击:
如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。