React.memo, useMemo, useCallback
리액트 렌더링 최적화를 위한 기법
컴포넌트가 리렌더링되는 조건
props가 변경될 때state가 변경될 때Memoization : 메모이제이션이란, 비용이 많이 드는 함수 호출의 결과를 저장하고 동일한 입력이 다시 발생할 때 캐시된 결과를 반환하여 컴퓨터 프로그램의 속도를 높이는데 주로 사용되는 최적화 기술이다.
HOC(Higher Order Component)는 공통된 로직을 수행하여 필요힌 결과물을 표현할 수 있도록 한다.
props가 변경된 경우에만 다시 렌더링된다.react는 부모 컴포넌트가 리렌더링되면 자식 컴포넌트도 리렌더링된다.
부모 컴포넌트 A에 자식 컴포넌트 B, C, D가 있다고 가정하자.
D에 CARD들이 무수히 많다면 그 CARD들 또한 전부 리렌더링된다.D 컴포넌트를 React.memo로 묶으면 A가 리렌더링되어도 D와 CARD들은 불필요한 리렌더링을 하지 않는다.
A에서 D로 props를 전달한다면, props가 다른 경우에만 D를 리렌더링한다.
React.memo는 props를 얕은 비교(객체의 주소값을 비교)하여 다른 경우에만 리렌더링한다.A 컴포넌트에서 함수나 객체를 props로 전달한다면 D 컴포넌트는 리렌더링 된다. A 컴포넌트의 함수와 객체는 리렌더링되면 새로운 주소값을 가지게 되기 때문.따라서 props 보단 string으로 값을 전달하는 것이 좋다.
import React from 'react';
const MyComponent = React.memo(({ prop1, prop2 }) => {
// render component based on prop1 and prop2
});
export default MyComponent;
동일한 값을 반환하는 함수를 반복적으로 호출해야한다면 처음 값을 계산할 때 해당 값을 메모리에 저장해 필요할 때마다 다시 계산하지 않고 메모리에서 꺼내서 재사용하는 것이다.
useMemo()를 사용하면 연산된 결과 값을 캐싱해주기 때문에, 매렌더링마다 고비용 연산이 일어나는 것을 방지할 수 있습니다.
useMemo()는 연산된 결과값이 바뀌지 않는다면 재연산이 일어나지 않는다.
고비용 연산을 방지하기 위해 사용하지만, 메모할 만큼 어려운 연산이 나리 때는 제거해야 공간을 절약할 수 있다.
import React, { useMemo } from 'react';
const MyComponent = ({ data }) => {
const result = useMemo(() => {
// ...
return computedResult;
}, [data]); // data가 바뀔 때만 함수가 실행된다.
return (
// ...
useCallback은 함수를 메모화하는 데 사용한다.
useMemo()와 메커니즘은 같지만, 값이 아닌 함수 자체를 캐싱한다는 차이가 있다.
useCallback을 사용하지 않는 경우
const PageMemoized = React.memo(Page);
const App = () => {
const [state, setState] = useState(1);
const onClick = () => {
console.log('Do something on click');
};
return (
// ...
// onClick이 계속 새로 만들어지기 때문에 memo를 사용해도 계속 리렌더링된다.
<PageMemoized onClick={onClick} />);
};
useCallback을 사용하는 경우const PageMemoized = React.memo(Page);
const App = () => {
const [state, setState] = useState(1);
const onClick = useCallback(() => {
console.log('Do something on click');
}, []);
return (
// onClick을 memoization 해서 Page 리렌더링을 막는다.
<PageMemoized onClick={onClick} />
);
};
대부분의 경우엔 useMemo와 useCallback을 사용하지 않는다.
첫 렌더링 때 값을 캐시해야 하므로, 상당한 지연시간이 생길 수 있다. 컴퓨터 자원이 낭비되고 애플리케이션이 느려질 가능성이 있다.
단순히 값이나 함수를 메모이제이션하는 것은 성능이 미미한 영향을 끼치거나 오히려 악영향이다.
따라서 위 기능들은 하위 컴포넌트가 리렌더링되는 것을 막기 위해서만 사용하는 것이 옳다.