반응형
1. React.memo를 사용한 컴포넌트 메모이제이션
React.memo
는 함수형 컴포넌트의 결과를 메모이징(기억)하여, 불필요한 리렌더링을 방지합니다.
작동 원리:
- 컴포넌트의 props를 얕은 비교(shallow compare)합니다.
- props가 변경되지 않았다면, 이전에 렌더링된 결과를 재사용합니다.
사용 예시:
import React from 'react';
const ExpensiveComponent = React.memo(({ data, onItemClick }) => {
console.log('ExpensiveComponent rendered');
return (
<ul>
{data.map(item => (
<li key={item.id} onClick={() => onItemClick(item.id)}>
{item.name}
</li>
))}
</ul>
);
});
// 사용
function ParentComponent() {
const [count, setCount] = useState(0);
const data = useMemo(() => [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
], []);
const handleItemClick = useCallback((id) => {
console.log('Item clicked:', id);
}, []);
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment: {count}</button>
<ExpensiveComponent data={data} onItemClick={handleItemClick} />
</div>
);
}
이 예시에서 ParentComponent
의 count
상태가 변경되어도 ExpensiveComponent
는 리렌더링되지 않습니다. data
와 onItemClick
이 메모이제이션되어 있기 때문입니다.
주의사항:
- 모든 컴포넌트를
React.memo
로 감싸는 것은 오히려 성능을 저하시킬 수 있습니다. - 복잡한 객체나 함수를 props로 전달할 때는
useMemo
나useCallback
과 함께 사용해야 효과적입니다.
2. useMemo 훅을 이용한 계산 결과 메모이제이션
useMemo
는 계산 비용이 높은 연산의 결과를 저장하고 재사용합니다.
작동 원리:
- 첫 번째 인자로 전달된 함수의 결과를 메모이징합니다.
- 두 번째 인자로 전달된 의존성 배열의 값이 변경될 때만 함수를 재실행합니다.
사용 예시:
import React, { useMemo, useState } from 'react';
function ExpensiveCalculation({ data }) {
const [filter, setFilter] = useState('');
const filteredData = useMemo(() => {
console.log('Calculating filtered data...');
return data.filter(item => item.name.toLowerCase().includes(filter.toLowerCase()));
}, [data, filter]); // data 또는 filter가 변경될 때만 재계산
return (
<div>
<input
type="text"
value={filter}
onChange={(e) => setFilter(e.target.value)}
placeholder="Filter items"
/>
<ul>
{filteredData.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
이 예시에서 filteredData
는 data
또는 filter
가 변경될 때만 재계산됩니다. 다른 상태 변경으로 인한 리렌더링에서는 이전에 계산된 결과를 재사용합니다.
주의사항:
- 모든 계산에
useMemo
를 사용하는 것은 불필요합니다. 계산 비용이 높거나 자주 리렌더링되는 컴포넌트에서만 사용하세요. - 의존성 배열을 올바르게 설정하지 않으면 오래된 데이터를 사용할 risk가 있습니다.
3. useCallback을 이용한 함수 메모이제이션
useCallback
은 콜백 함수를 메모이징하여, 불필요한 리렌더링을 방지합니다.
작동 원리:
- 첫 번째 인자로 전달된 콜백 함수를 메모이징합니다.
- 두 번째 인자로 전달된 의존성 배열의 값이 변경될 때만 새로운 함수를 생성합니다.
사용 예시:
import React, { useState, useCallback } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('Button clicked');
setCount(prevCount => prevCount + 1);
}, []); // 의존성 배열이 비어있으므로 컴포넌트가 마운트될 때만 함수가 생성됨
return (
<div>
<ChildComponent onClick={handleClick} />
<p>Count: {count}</p>
</div>
);
}
const ChildComponent = React.memo(({ onClick }) => {
console.log('ChildComponent rendered');
return <button onClick={onClick}>Click me</button>;
});
이 예시에서 handleClick
함수는 컴포넌트가 처음 렌더링될 때만 생성되며, 이후 리렌더링에서는 동일한 함수 참조를 유지합니다. 이로 인해 ChildComponent
는 불필요하게 리렌더링되지 않습니다.
주의사항:
useCallback
은 함수 생성 자체를 최적화하는 것이 아니라, 함수의 참조가 변경되는 것을 방지합니다.- 의존성 배열을 신중히 설정해야 합니다. 빈 배열을 사용하면 함수가 오래된 클로저를 참조할 수 있습니다.
이러한 기법들을 적절히 조합하여 사용하면 React 애플리케이션의 성능을 크게 향상시킬 수 있습니다. 하지만 항상 성능 측정을 통해 실제로 최적화가 필요한 부분에 적용하는 것이 중요합니다.
반응형