当前位置:首页 > 科技  > 软件

现在停止滥用useMemo吧!

来源: 责编: 时间:2024-06-05 17:46:32 213观看
导读在React应用中过度优化真的是一种噩梦。我们每天都要面对大量无用的优化,这些优化意在使代码变得“神秘”。一些开发人员甚至将 useMemo 和 useCallback 纳入他们的默认风格指南中,以简化事情。不要陷入这种迷思,因为 us

mxI28资讯网——每日最新资讯28at.com

在React应用中过度优化真的是一种噩梦。我们每天都要面对大量无用的优化,这些优化意在使代码变得“神秘”。一些开发人员甚至将 useMemo 和 useCallback 纳入他们的默认风格指南中,以简化事情。不要陷入这种迷思,因为 useMemo 甚至可能会减慢你的应用程序速度!记住,记忆化并不是免费的。mxI28资讯网——每日最新资讯28at.com

在这篇文章中,向你展示大多数开发人员如何过度使用 useMemo 钩子,并提供一些避免这种情况的技巧。当我第一次意识到我犯了这些错误时,我感到非常愚蠢。话不多说,开始吧!mxI28资讯网——每日最新资讯28at.com

为什么我们使用useMemo?

useMemo 是一个允许我们在组件重新渲染之间缓存计算结果的钩子。毫无疑问,它仅用于性能原因,并且应该与其他技术如 React.memo、useCallback、debouncing、并发渲染等一起使用。mxI28资讯网——每日最新资讯28at.com

尽管在某些情况下,这个钩子确实有帮助,并且发挥了重要作用,但大多数开发人员却错误地使用它。他们将每个变量都用 useMemo 包裹起来,希望随机的优化能带来成功。不出所料,这种方法只会导致代码可读性差和内存使用增加。mxI28资讯网——每日最新资讯28at.com

另一个需要记住的重要事项是,useMemo 只有在重新渲染阶段才有价值。在初始化期间,记忆化(memoization)会减慢应用程序的速度,并且这种影响会逐渐累积。这就是我所说的“记忆化并不是免费的”的意思。mxI28资讯网——每日最新资讯28at.com

什么时候它没有用甚至有害?

现在,看看下面的例子。这些都是我从一个项目中拿来的真实代码片段。你能说出哪个useMemo的使用实际上有意义吗?mxI28资讯网——每日最新资讯28at.com

export const NavTabs = ({ tabs, className, withExpander }) => {  const currentMainPath = useMemo(() => {    return pathname.split("/")[1];  }, [pathname]);  const isCurrentMainPath = useMemo(() => {    return currentMainPath === pathname.substr(1);  }, [pathname, currentMainPath]);  return (    <StyledWrapper>      <Span fontSize={18}>        {isCurrentMainPath ? (          t(currentMainPath)        ) : (          <StyledLink to={`/${currentMainPath}`}>            {t(currentMainPath)}          </StyledLink>        )}      </Span>    </StyledWrapper>  );};

通常我们在两种情况下使用 useMemo:记住一个引用并将其传递给 memo 组件,或缓存一些昂贵的计算。mxI28资讯网——每日最新资讯28at.com

现在想一想,我们在上面的例子中优化了什么?我们有原始值,并没有将任何更深层次的内容传递到组件树中,所以我们不需要保留引用。而且.split和===似乎不是需要记忆化的复杂计算。因此,我们可以轻松地在这个例子中去掉useMemo,节省一些文件空间 :)mxI28资讯网——每日最新资讯28at.com

export const Client = ({ clientId, ...otherProps }) => {  const tabs = useMemo(    () => [      {        label: t("client withdrawals"),        path: `/clients/${clientId}/withdrawals`      },      ...    ],    [t, clientId]  );    ...    return (    <>      ...      <NavTabs tabs={tabs} />    </>  )}export const NavTabs = ({ tabs, className, withExpander }) => {  return (    <Wrapper className={className} withExpander={withExpander}>      {tabs.map((tab) => (        <Item          key={tab.path}          to={tab.path}          withExpander={withExpander}        >          <StyledLabel>{tab.label}</StyledLabel>        </Item>      ))}    </Wrapper>  );};

在上面的例子中,我们将tabs变量记忆化,然后将其传递给 NavTabs。你认为优化tabs创建的主要意图是什么?这根本不是一个计算问题,所以实现它的人可能是想要保留引用并避免 NavTabs 的过度重新渲染。这在这里是正确的做法吗?mxI28资讯网——每日最新资讯28at.com

首先,NavTabs 是一个轻量级组件,可以多次重新渲染而不影响性能。其次,即使它是一个重量级组件,useMemo 也不会起作用。仅仅保留引用不足以防止 NavTabs 在每次Client组件重新渲染时重新渲染。为了优化性能,我们应该用React.memo包裹 NavTabs。mxI28资讯网——每日最新资讯28at.com

memo 函数返回我们组件的记忆化版本。只要它的 props 没有改变,这个版本通常不会在其父组件重新渲染时重新渲染。memo 使用浅比较props来决定组件是否应该更新。如果你有一些特定条件来决定组件何时应该重新渲染,你甚至可以指定自己的比较函数作为 memo 的第二个参数。mxI28资讯网——每日最新资讯28at.com

如何判断计算是否昂贵?

除非你在执行成千上万项复杂循环或计算阶乘,否则它可能不昂贵。你可以结合使用React Profiler和performance.now()来识别瓶颈,然后再应用优化技术。mxI28资讯网——每日最新资讯28at.com

避免在以下情况下使用 useMemo:mxI28资讯网——每日最新资讯28at.com

  • 试图优化的计算很便宜。在这些情况下,使用useMemo的开销将超过其带来的好处。
  • 不确定是否需要记忆化。最好先不使用它,然后在出现问题时逐步将优化引入代码。
  • 记忆化的值没有传递到组件中。如果该值仅在JSX中使用,并且没有传递到组件树中,大多数情况下你可以避免优化。没有必要记住它的引用,因为它不会影响其他组件的重新渲染。
  • 依赖数组变化太频繁。在这种情况下,useMemo不会带来任何性能优势,因为它每次都会重新计算。

如何正确使用的技巧

React 组件每次重新渲染时都会运行其主体,这发生在其道具或状态发生变化时。通常情况下,我们希望避免在渲染过程中进行昂贵的计算,因为它们会减慢组件的运行速度。mxI28资讯网——每日最新资讯28at.com

然而,大多数计算仍然非常快,因此很难理解哪些地方确实需要使用 useMemo。要开始有效且有目的性地进行优化,首先应找出问题所在。此外,不要忘记其他技术,例如:useCallback、React.memo、debouncing、代码拆分、lazy-loading 等。mxI28资讯网——每日最新资讯28at.com

我们看下面一个非常简单的例子。doCalculation 是一个人为放慢速度的函数,因此它需要 500ms 才能返回一个随机数。那么我们在这里遇到了什么问题呢?是的,每次值更新时,我们都要重新计算我们的重函数,这使得使用输入变得非常困难。mxI28资讯网——每日最新资讯28at.com

function doCalculation() {  const now = performance.now();  while (performance.now() - now < 500) {    // 停顿500毫秒  }  return Math.random();}export default function App() {  const [value, setValue] = useState(0);  const calculation = doCalculation();  return (    <div>      <input value={value} onChange={(e) => setValue(e.target.value)} />      <h1>{`Calculation is ${calculation}`}</h1>    </div>  );}

我们如何解决这个问题?只需用useMemo包裹doCalculation而不加任何依赖项。mxI28资讯网——每日最新资讯28at.com

const calculation = useMemo(() => doCalculation(), []);

现场实例:mxI28资讯网——每日最新资讯28at.com

https://codesandbox.io/s/happy-grass-0mjpbw?from-embed。mxI28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-92175-0.html现在停止滥用useMemo吧!

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Spring Boot 性能太差?试试这几招!

下一篇: 项目亮点:分析与解决小程序页面切换过程卡顿的问题

标签:
  • 热门焦点
  • 一个注解实现接口幂等,这样才优雅!

    场景码猿慢病云管理系统中其实高并发的场景不是很多,没有必要每个接口都去考虑并发高的场景,比如添加住院患者的这个接口,具体的业务代码就不贴了,业务伪代码如下:图片上述代码有
  • 微软邀请 Microsoft 365 商业用户,测试视频编辑器 Clipchamp

    8 月 1 日消息,微软近日宣布即将面向 Microsoft 365 商业用户,开放 Clipchamp 应用,邀请用户通过该应用来编辑视频。微软于 2021 年收购 Clipchamp,随后开始逐步整合到 Microsof
  • Temu起诉SHEIN,跨境电商战事升级

    来源 | 伯虎财经(bohuFN)作者 | 陈平安日前据外媒报道,拼多多旗下跨境电商平台Temu正对竞争对手SHEIN提起新诉讼,诉状称Shein&ldquo;利用市场支配力量强迫服装厂商与之签订独家
  • 破圈是B站头上的紧箍咒

    来源 | 光子星球撰文 | 吴坤谚编辑 | 吴先之每年的暑期档都少不了瞄准追剧女孩们的古偶剧集,2021年有优酷的《山河令》,2022年有爱奇艺的《苍兰诀》,今年却轮到小破站抓住了追
  • 一条抖音4亿人围观 ! 这家MCN比无忧传媒还野

    作者:Hiu 来源:互联网品牌官01 擦边少女空降热搜,幕后推手曝光被网友誉为&ldquo;纯欲天花板&rdquo;的女网红井川里予,近期因为一组哥特风照片登上热搜,引发了一场互联网世界关于
  • Android 14发布:首批适配机型公布

    5月11日消息,谷歌在今天凌晨举行了I/O大会,本次发布会谷歌带来了自家的AI语言模型PaLM 2、谷歌Pixel Fold折叠屏、谷歌Pixel 7a手机,同时发布了Androi
  • 荣耀Magicbook V 14 2021曙光蓝版本正式开售,拥有触摸屏

    荣耀 Magicbook V 14 2021 曙光蓝版本正式开售,搭载 i7-11390H 处理器与 MX450 显卡,配备 16GB 内存与 512GB SSD,重 1.48kg,厚 14.5mm,具有 1.5mm 键盘键程、
  • DRAM存储器10月价格下跌,NAND闪存本月价格与上月持平

    10月30日,据韩国媒体消息,自今年年初以来一直在上涨的 DRAM 存储器的交易价格仅在本月就下跌了近 10%,此次是全年首次降价,而NAND 闪存本月价格与上月持平。市
  • 电博会与软博会实现"线下+云端"的双线融合

    在本次“电博会”与“软博会”双展会利好条件的加持下,既可以发挥展会拉动人流、信息流、资金流实现快速交互流动的作用,继而推动区域经济良性发展;又可以聚
Top