日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

現在停止濫用useMemo吧!

來源: 責編: 時間:2024-06-05 17:46:32 149觀看
導讀在React應用中過度優化真的是一種噩夢。我們每天都要面對大量無用的優化,這些優化意在使代碼變得“神秘”。一些開發人員甚至將 useMemo 和 useCallback 納入他們的默認風格指南中,以簡化事情。不要陷入這種迷思,因為 us

cKF28資訊網——每日最新資訊28at.com

在React應用中過度優化真的是一種噩夢。我們每天都要面對大量無用的優化,這些優化意在使代碼變得“神秘”。一些開發人員甚至將 useMemo 和 useCallback 納入他們的默認風格指南中,以簡化事情。不要陷入這種迷思,因為 useMemo 甚至可能會減慢你的應用程序速度!記住,記憶化并不是免費的。cKF28資訊網——每日最新資訊28at.com

在這篇文章中,向你展示大多數開發人員如何過度使用 useMemo 鉤子,并提供一些避免這種情況的技巧。當我第一次意識到我犯了這些錯誤時,我感到非常愚蠢。話不多說,開始吧!cKF28資訊網——每日最新資訊28at.com

為什么我們使用useMemo?

useMemo 是一個允許我們在組件重新渲染之間緩存計算結果的鉤子。毫無疑問,它僅用于性能原因,并且應該與其他技術如 React.memo、useCallback、debouncing、并發渲染等一起使用。cKF28資訊網——每日最新資訊28at.com

盡管在某些情況下,這個鉤子確實有幫助,并且發揮了重要作用,但大多數開發人員卻錯誤地使用它。他們將每個變量都用 useMemo 包裹起來,希望隨機的優化能帶來成功。不出所料,這種方法只會導致代碼可讀性差和內存使用增加。cKF28資訊網——每日最新資訊28at.com

另一個需要記住的重要事項是,useMemo 只有在重新渲染階段才有價值。在初始化期間,記憶化(memoization)會減慢應用程序的速度,并且這種影響會逐漸累積。這就是我所說的“記憶化并不是免費的”的意思。cKF28資訊網——每日最新資訊28at.com

什么時候它沒有用甚至有害?

現在,看看下面的例子。這些都是我從一個項目中拿來的真實代碼片段。你能說出哪個useMemo的使用實際上有意義嗎?cKF28資訊網——每日最新資訊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 組件,或緩存一些昂貴的計算。cKF28資訊網——每日最新資訊28at.com

現在想一想,我們在上面的例子中優化了什么?我們有原始值,并沒有將任何更深層次的內容傳遞到組件樹中,所以我們不需要保留引用。而且.split和===似乎不是需要記憶化的復雜計算。因此,我們可以輕松地在這個例子中去掉useMemo,節省一些文件空間 :)cKF28資訊網——每日最新資訊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 的過度重新渲染。這在這里是正確的做法嗎?cKF28資訊網——每日最新資訊28at.com

首先,NavTabs 是一個輕量級組件,可以多次重新渲染而不影響性能。其次,即使它是一個重量級組件,useMemo 也不會起作用。僅僅保留引用不足以防止 NavTabs 在每次Client組件重新渲染時重新渲染。為了優化性能,我們應該用React.memo包裹 NavTabs。cKF28資訊網——每日最新資訊28at.com

memo 函數返回我們組件的記憶化版本。只要它的 props 沒有改變,這個版本通常不會在其父組件重新渲染時重新渲染。memo 使用淺比較props來決定組件是否應該更新。如果你有一些特定條件來決定組件何時應該重新渲染,你甚至可以指定自己的比較函數作為 memo 的第二個參數。cKF28資訊網——每日最新資訊28at.com

如何判斷計算是否昂貴?

除非你在執行成千上萬項復雜循環或計算階乘,否則它可能不昂貴。你可以結合使用React Profiler和performance.now()來識別瓶頸,然后再應用優化技術。cKF28資訊網——每日最新資訊28at.com

避免在以下情況下使用 useMemo:cKF28資訊網——每日最新資訊28at.com

  • 試圖優化的計算很便宜。在這些情況下,使用useMemo的開銷將超過其帶來的好處。
  • 不確定是否需要記憶化。最好先不使用它,然后在出現問題時逐步將優化引入代碼。
  • 記憶化的值沒有傳遞到組件中。如果該值僅在JSX中使用,并且沒有傳遞到組件樹中,大多數情況下你可以避免優化。沒有必要記住它的引用,因為它不會影響其他組件的重新渲染。
  • 依賴數組變化太頻繁。在這種情況下,useMemo不會帶來任何性能優勢,因為它每次都會重新計算。

如何正確使用的技巧

React 組件每次重新渲染時都會運行其主體,這發生在其道具或狀態發生變化時。通常情況下,我們希望避免在渲染過程中進行昂貴的計算,因為它們會減慢組件的運行速度。cKF28資訊網——每日最新資訊28at.com

然而,大多數計算仍然非常快,因此很難理解哪些地方確實需要使用 useMemo。要開始有效且有目的性地進行優化,首先應找出問題所在。此外,不要忘記其他技術,例如:useCallback、React.memo、debouncing、代碼拆分、lazy-loading 等。cKF28資訊網——每日最新資訊28at.com

我們看下面一個非常簡單的例子。doCalculation 是一個人為放慢速度的函數,因此它需要 500ms 才能返回一個隨機數。那么我們在這里遇到了什么問題呢?是的,每次值更新時,我們都要重新計算我們的重函數,這使得使用輸入變得非常困難。cKF28資訊網——每日最新資訊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而不加任何依賴項。cKF28資訊網——每日最新資訊28at.com

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

現場實例:cKF28資訊網——每日最新資訊28at.com

https://codesandbox.io/s/happy-grass-0mjpbw?from-embed。cKF28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-92175-0.html現在停止濫用useMemo吧!

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Spring Boot 性能太差?試試這幾招!

下一篇: 項目亮點:分析與解決小程序頁面切換過程卡頓的問題

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 吴旗县| 甘谷县| 罗城| 新晃| 丰城市| 剑川县| 石棉县| 道真| 襄汾县| 商河县| 文山县| 满洲里市| 靖州| 四会市| 唐河县| 绥江县| 广平县| 图们市| 长白| 旬邑县| 遂平县| 洛浦县| 宁阳县| 新乐市| 江达县| 安阳市| 游戏| 天长市| 万全县| 宕昌县| 新竹县| 桂阳县| 壶关县| 平果县| 栾城县| 铜梁县| 富顺县| 剑河县| 库伦旗| 正定县| 武清区|