일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 빡킹독
- 노마드 코더 #타입스크립트 #typescript #class
- React #리액트 이벤트 주기 #리액트 이벤트
- 다익스트라 #파티 #백준
- React #controlled component #비제어 컴포넌트 #제어 컴포넌트
- raect typescript #react #typescript #styled-component
- 얕은 복사 #깊은 복사 #shallow copy #deep copy
- react
- interceptors
- axios
- RateLimit
- 백준 #적록색약
- JWT #토큰 #refreshToken #accessToken #Token #token #localStorage #sessionStorage
- 백준 #직각삼각형
- React #Hook rules #Hook 규칙
- #useRef #언제 쓰는데?
- npm #not being able to find a file #npm install Error
- React-Query
- useState #Hooks
- html entities
- rate limit
- react #useCallback #react Hook
- React #effect hook #useEffect
- 코드스테이츠 #알고리즘 #그리디
- 이친수
- 플로이드 #c++
- react fragment
- DP #c++
- donwstream #upstream #origin
- 버블링 #갭쳐링 #이벤트 #JS
- Today
- Total
꿈꾸는 개발자
useMemo를 사용하는 기준 - (언제 사용하나? 지양하는 게 더 좋다!?!) 본문
원티드 프론트엔드 최적화 강의를 들었을 때 현업에서는 useMemo, useCallback을 자주 사용하지 않는다는 말을 들었다.
https://javascript.plainenglish.io/stop-using-usememo-now-e5d07d2bbf70#5aca
위 링크는 useMemo를 난발하면 안 좋은 점과 최적화가 아닌, 오히려 App의 성능을 저하할 수도 있다고 말한다. 컴퓨터공학은 항상 trade-off를 고려해야 한다. 이 말은 즉슨 최적화에 따른 댓가가 분명 있다는 것!
일차적으로 useMemo, 그 자체보단 React.memo, useCallback debouncing concurrent rendering 등과 합쳐져야 한다. 저자에 따르면, useMemo 등의 최적화 과정은 분명히 도움이 되는 곳이 있지만, 모든 value에 useMemo를 사용 후 적절한 최적화가 되기를 바라는 것은 적합하지 않다고 말한다. 이는 오히려 메모리 사용량을 증가시킬 뿐이다!
useMemo는 re-render phase에서 value를 가져온다. 따라서, 초기화 및 메모제이션 과정에서 app 자체의 속도를 저하시킨다.
보통 useMemo를 사용하는 경우는
- 복잡한 계산이 들어가는 경우
- Memoized component을 전달하는 경우
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를 제거해도 무방하다는 것이다.
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>
);
};
위 코드의 경우 useMemo보단, React.memo를 사용해서 부모 컴포넌트가 re-rendering되더라도, props의 변화가 없는 한 재랜더링되지 않도록 코드를 작성해야 적절한 optimization이 된다. (React.memo의 경우 shallow compraison을 시행하지만, 두 번째 arg로 사용자가 원하는 검사 조건을 추가할 수 있다)
계산이 복잡하다는 것의 기준은?
thousands의 items의 계산, 팩토리얼 계산이 아닌 이상 대체적으로 복잡한 계산에 속하지 않는다! Profiler을 활용해 optimization이 필요한 컴포넌트를 찾을 수 있다.
https://react.dev/learn/you-might-not-need-an-effect
추가로 위 React 공식문서에 따르면,
console.time('filter array');
const visibleTodos = getFilteredTodos(todos, filter);
console.timeEnd('filter array');
위 처럼 시간을 측정하는 함수를 통해 함수 실행 시간을 측정했을 때 1ms 이상일 경우에만 useMemo의 사용을 고려해도 좋다고 말한다. useMemo를 사용한 후 동일하게 실행 시간이 유의미하게 감소했는지 확인 해보는 것도 좋다.
기억해야 할 것은: useMemo는 첫 번째 render를 빠르게 해주는 게 아니라, memoization을 re-render을 빠르게 해주는 것이기 때문에 잘 판단하고 사용하는 게 중요하다.
이러한 경우에는 useMemeo를 사용하지 마라!
- 가벼운 계산일 경우
- memoization이 필요한지 애매한 경우: 처음에는 제외하고 나중에 문제가 생기면 추가하는 것이 좋다.
- memoizing하고 있는 값이 component에 전달되지 않는 경우
- dependency array가 너무 자주 변동되는 경우:
적확하게 사용하는 꿀팁!
React component는 props나 state가 change될 때마다 re-rendering이 발생한다. 따라서, rendering 단계에서 최적화를 하기 위해서는 문제에 대한 근본적인 판단이 우선이 되어야 한다. 나아가, React.memo, debouncing, code-splitting, lazy-loading 등을 항상 고려하는 것도 중요하다.