우선, 메모리제이션의 정의는 다음과 같습니다.
React에서 메모이제이션(Memoization)은 컴포넌트가 리렌더링될 때 불필요한 재계산이나 함수 재생성을 방지하여 성능을 최적화하는 기법입니다. 메모이제이션을 사용하면 이전 계산 결과를 저장해두고, 동일한 입력이 들어오면 저장된 결과를 재사용하게 됩니다. 이를 통해 계산 비용이 높은 작업이나 함수 재생성에 소모되는 자원을 절약할 수 있습니다.
그렇다면 메모이제이션을 구현하는 방법은 어떤 것들이 있을까요?
우선 useMemo부터 소개하겠습니다.
useMemo는 복잡한 계산이 포함된 값을 메모이제이션하여, 특정 의존성이 변경될 때만 재계산되도록 합니다.
import React, { useMemo } from 'react';
function MyComponent({ items }) {
// `items`가 변경될 때만 `sortedItems`가 다시 계산됩니다.
const sortedItems = useMemo(() => {
return items.sort((a, b) => a - b);
}, [items]);
return (
<ul>
{sortedItems.map(item => (
<li key={item}>{item}</li>
))}
</ul>
);
}
useMemo를 사용하지 않으면, 컴포넌트가 리렌더링될 때마다 sortedItems가 매번 재계산될 수 있습니다. 이는 items 외의 상태나 props가 변경되었을 때도 영향을 미칠 수 있습니다.
useMemo는 의존성 배열에 명시된 값(items)이 변경될 때만 sortedItems를 재계산하므로, 불필요한 계산을 줄이고 성능을 최적화할 수 있습니다.
useCallback은 컴포넌트가 리렌더링될 때마다 동일한 함수가 재생성되지 않도록 합니다. 주로 자식 컴포넌트에 콜백 함수를 전달할 때 사용하여, 자식 컴포넌트의 불필요한 리렌더링을 방지할 수 있습니다.
import React, { useCallback } from 'react';
function MyComponent({ onClick }) {
// `onClick`이 변경될 때만 `handleClick` 함수가 재생성됩니다.
const handleClick = useCallback(() => {
onClick('Clicked!');
}, [onClick]);
return (
<button onClick={handleClick}>Click me</button>
);
}
onClick 함수가 새로운 참조를 가지게 되면 (예를 들어, 부모 컴포넌트에서 매번 다른 함수가 전달되는 경우), useCallback은 새 함수로 handleClick을 업데이트합니다. 반면, onClick이 동일한 참조를 유지하면, handleClick은 이전에 저장된 참조를 재사용합니다.
React.memo는 컴포넌트가 동일한 props로 리렌더링되는 경우, 이전에 렌더링된 결과를 재사용하여 불필요한 리렌더링을 방지합니다.
import React from 'react';
// 자식 컴포넌트를 메모이제이션하여 불필요한 리렌더링을 방지
const ChildComponent = React.memo(({ value }) => {
console.log('Rendering ChildComponent');
return <div>{value}</div>;
});
function ParentComponent() {
const [count, setCount] = React.useState(0);
return (
<div>
<ChildComponent value={count} />
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
React.memo는 ChildComponent에 전달되는 props가 변경되지 않는 한 컴포넌트의 리렌더링을 방지합니다.
ParentComponent의 count 값이 변경되면, ParentComponent는 리렌더링되지만, ChildComponent는 value prop이 동일하기 때문에 리렌더링되지 않습니다. 즉, value가 동일하게 유지되는 한 ChildComponent는 렌더링되지 않습니다.
이로 인해 ChildComponent의 불필요한 리렌더링이 방지되어 성능이 향상됩니다.
useMemo, useCallback, React.memo 등 다양한 메모이제이션 기법을 이해하고 적절한 상황에서 사용하는 것이 중요합니다.
복잡한 계산이나 자주 변경되는 함수, 또는 리렌더링 성능을 최적화할 때 메모이제이션을 적극적으로 활용할 수 있습니다.
메모이제이션을 적용한 후에는 성능 측정을 통해 실제로 성능이 개선되었는지 검토하는 것이 좋습니다.
React의 DevTools와 같은 도구를 사용하여 성능 분석을 하고, 실제 애플리케이션의 성능에 미치는 영향을 파악합니다.