React 리팩토링 - 불필요한 연산을 줄여보자, props를 복사해서 사용하지 않기, useMemo 사용하기
useMemo란?
useMemo는 React에서 컴포넌트 성능 최적화를 위해 제공하는 훅입니다. 특정 값이 재계산될 필요가 없을 때 이전 계산 값을 재사용하여 불필요한 계산을 방지합니다.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
1. 불필요한 계산 방지
- 복잡한 계산(비용이 많이 드는 함수 호출 등)의 결과를 캐싱합니다.
- 종속성 배열([])의 값이 변경될 때만 재계산이 일어납니다.
2. 참조 유지
- 이전에 계산된 값을 재사용하므로 매번 새로운 값 생성이 방지됩니다.
- 이는 React에서 props 전달 시 메모이제이션된 객체나 배열의 참조를 유지하는 데도 유용합니다.
예시
1. 비용이 큰 계산 로직 - items가 변경될 때만 filter 함수가 호출됩니다.
const filteredItems = useMemo(() => {
return items.filter(item => item.active);
}, [items]);
2. 렌더링 성능 최적화: 컴포넌트가 자주 렌더링되면서 불필요한 값 재계싼이 발생하는 경우
function ExpensiveComponent({ data }) {
const sortedData = useMemo(() => {
return data.sort((a, b) => a.value - b.value);
}, [data]);
return <div>{sortedData.join(', ')}</div>;
}
3. 객체나 배열의 참조 유지
- React는 참조형 값(객체, 배열)을 비교할 때 참조가 동일하지 않으면 변경된 것으로 간주합니다.
- useMemo를 사용하면 동일한 참조를 유지하여 불필요한 리렌더링을 방지합니다.
const memoizedOptions = useMemo(() => ({ key: 'value' }), []);
useMemo와 useCallback의 사용 기준
1. 값을 메모이제이션해야 한다면?
복잡한 계산 결과를 재활용하고 싶으면 useMemo
2. 함수 참조를 메모이제이션해야 한다면?
자식 컴포넌트가 불필요한 리렌더링을 방지하려면 useCallback
주요 사용 시나리오
1. useMemo
- 데이터 필터링, 정렬, 계산 같은 무거운 연산
- 값이 변경되지 않으면 연산 결과를 재활용
- 예: 리스트 필터링 결과
2. useCallback
- 함수가 자식 컴포넌트에 props로 전달될 때
- 함수 참조가 변경되지 않아야 리렌더링을 방지
- 예: 이벤트 핸들러, 콜백 함수
값을 캐싱해야 한다면 useMemo, 함수 참조를 유지해야 한다면 useCallback을 사용하세요.