React.js의 최적화 방법 중 가장 간단하고 사용이 쉬운 것은 useMemo와 useCallback이다. 연산의 결과값 또는 한번 생성 된 함수를 메모리에 기억시켜두고, 컴포넌트가 리렌더링 될 때마다 연산을 다시 하거나 함수를 다시 생성 하지 않고 저장된 값 또는 함수를 그대로 꺼내와서 자원이 낭비되지 않도록 한다.
한번 연산이 완료된 결과값을 메모리에 저장시켜두었다가 사용할 수 있게 해주는 함수.
const memoizedValue = useMemo(() => expensiveCalculation(a, b), [a, b]);
memoizedValue는 리렌더링이 일어나도 useMemo에 의해 다시 렌더링이 일어나는 것이 방지된다. 다만 디펜던시에 의해 a 혹은 b의 값이 변경될 경우에는 연산을 다시 실행한다.
한번 생성이 완료된 함수를 메모리에 저장시켜두었다가 사용할 수 있게 해주는 함수.
const memoizedCallback = useCallback(() => {
}, [dependency]);
memoizedCallback 함수는 리렌더링이 일어나도 useCallback에 의해 다시 생성되는 것이 방지된다. 다만 디펜던시에 들어간 값이 변화할 경우에는 함수를 다시 생성한다.
여기까지만 보면 모든 연산 결과값과 함수에 useMemo와 useCallback를 사용하여 자원의 낭비를 막아 컴포넌트의 최적화를 꾀할 수 있다는 생각이 든다. 그러나..
성능 최적화는 아무런 댓가없이 공짜로 제공되는 것이 아니다.
Stop Using useMemo Now!
(번역) useMemo를 사용하는 것을 당장 멈추세요!
useMemo, useCallback를 사용할 경우 이들 역시 메모리를 자원으로 사용하게 된다. 따라서 App 전체에서 이들을 마구 남용할 경우 최적화를 위해 사용한 개념이 오히려 최적화를 방해하고, 나아가서 전체 성능을 나쁘게 만들 수 있다.
최적화하려는 계산의 비용이 크지 않은 경우에는 최적화를 하지 않는다.
연산을 하는데 시간이 오래 걸리고, 사용하는 데이터의 양이 거대하며, 해당 연산이 자주 발생하고, 리렌더링이 과도하게 이루어지는 등의 경우는 계산의 비용이 큰 경우이며 이럴 때에는 최적화가 필요하다.
최적화가 필요없는 부분에는 최적화를 하지 않는다.
단순히 숫자 몇 개를 계산하는 것이나 문자열을 받아 조금 가공하는 경우에는 최적화를 수행하는데 드는 비용이 더 크다. 이런 경우에는 최적화를 하지 말아야한다.
컴포넌트에서 사용되지 않는 값은 최적화가 필요없다.
React.js에서 성능 저하가 일어나는 원인 중 하나는 하나의 컴포넌트에서 발생된 리렌더링이 다른 컴포넌트에도 영향을 미쳐 연쇄적으로 리렌더링이 일어나는 것이다. 그런데 해당 값이 컴포넌트에서 사용되지 않는다면 리렌더링이 일어날 일이 없다.
디펜던시를 많이 사용해야하는 경우에는 최적화를 할 필요가 없다.
디펜던시에 속한 값이 변경될 때마다 useMemo와 useCallback 모두 다시 연산하거나 함수를 생성한다. 이 말은 디펜던시의 값이 자주 변화한다면 재연산이 자주 일어나게 되고, 이는 결국 최적화를 하는 의미가 퇴색되어버린다.