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
을 사용하지 않는다.
첫 렌더링 때 값을 캐시해야 하므로, 상당한 지연시간이 생길 수 있다. 컴퓨터 자원이 낭비되고 애플리케이션이 느려질 가능성이 있다.
단순히 값이나 함수를 메모이제이션하는 것은 성능이 미미한 영향을 끼치거나 오히려 악영향이다.
따라서 위 기능들은 하위 컴포넌트가 리렌더링되는 것을 막기 위해서만 사용하는 것이 옳다.