일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 코드잇
- 자바스크립트
- javascript
- 경제
- next
- 미국
- 프로젝트 회고
- typescript
- 리엑트 쿼리
- 경제신문읽기
- 코드잇 스프린트
- 은행
- 한국은행
- 개발자
- 개발
- 코드잇 스프린트 9기
- Next.js
- 가계부채
- 프론트엔드
- 내수
- 가계대출
- 금융투자소득세
- react
- 기준금리
- js
- API
- 금리
- 금투세
- CS
- FED
- Today
- Total
뭉균의 개발일지
[React] 메모이제이션(useMemo, useCallback, React.Memo) 본문
🚪 들어가며
리액트는 컴포넌트 기반의 UI 라이브러리로, 상태 변경 시 화면을 효율적으로 업데이트해주는 특성이 있습니다. 그러나 컴포넌트가 자주 재렌더링되는 경우 불필요한 계산이나 렌더링이 발생하여 성능 저하를 일으킬 수 있습니다. 이러한 성능 이슈는 주로 대규모 애플리케이션이나 복잡한 로직을 처리하는 컴포넌트에서 두드러지게 나타납니다.
리액트는 이런 문제를 해결하기 위해 메모이제이션(Memoization) 기능을 제공합니다. 메모이제이션은 특정 값이나 함수를 캐싱해두고, 동일한 입력 값에 대해 불필요한 재계산을 방지하는 최적화 기법입니다. 리액트에서 제공하는 useMemo, useCallback, 그리고 React.Memo는 이러한 성능 최적화를 위한 메모이제이션 도구입니다.
📌 useMemo의 개념과 사용법
useMemo란?
useMemo는 리액트에서 제공하는 훅으로, 계산 비용이 큰 연산을 메모이제이션하여, 값이 변경되지 않는 한 다시 계산하지 않도록 최적화합니다. 이를 통해 컴포넌트가 재렌더링될 때마다 불필요한 계산을 피할 수 있습니다.
useMemo를 사용하는 이유
useMemo는 일반적으로 계산이 무겁거나 반복되는 연산이 많은 경우에 사용합니다. 예를 들어, 배열을 필터링하거나 정렬하는 작업이 있을 때, 입력 값이 변하지 않는 한 같은 연산을 반복할 필요가 없으므로 useMemo로 최적화할 수 있습니다.
예제 코드
import React, { useMemo } from 'react';
const MyComponent = ({ items }) => {
const filteredItems = useMemo(() => { return items.filter(item => item.isActive); }, [items]); // items가 변경될 때만 필터링 실행
return ( <div> {filteredItems.map(item => ( <div key={item.id}>{item.name}</div> ))} </div> ); };
위의 예제에서 items 배열이 변경되지 않는 한 filteredItems는 다시 계산되지 않으며, 불필요한 연산을 피할 수 있습니다.
📌 useCallback의 개념과 사용법
useCallback이란?
useCallback은 메모이제이션된 콜백 함수를 반환하는 훅으로, 컴포넌트가 다시 렌더링될 때마다 동일한 함수 객체를 생성하지 않도록 도와줍니다. 주로 하위 컴포넌트에 콜백 함수를 전달할 때, 의도치 않은 리렌더링을 방지하는 데 사용됩니다.
useCallback을 사용하는 이유
리액트에서는 함수가 재정의되면 이전과 동일한 로직이더라도 새로운 함수 객체로 인식합니다.(객체의 주소값이 바뀌면서 props가 바뀐 것으로 인식) 하위 컴포넌트에 이러한 함수가 전달되면, 불필요한 리렌더링이 발생할 수 있습니다. useCallback을 사용하면 이러한 문제를 방지할 수 있습니다.
예제 코드
import React, { useState, useCallback } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const [count, setCount] = useState(0); // 콜백 함수 메모이제이션
const handleClick = useCallback(() => { setCount(count + 1); }, [count]); // count가 변경될 때만 새로운 함수 생성
return ( <div> <ChildComponent onClick={handleClick} /> <p>{count}</p> </div> );
};
위의 예제에서 handleClick 함수는 count가 변경될 때만 재생성되며, 그 외의 경우 동일한 함수 객체가 하위 컴포넌트에 전달됩니다. 이를 통해 불필요한 리렌더링을 방지할 수 있습니다.
📌 React.Memo의 개념과 사용법
React.Memo란?
React.Memo는 컴포넌트를 메모이제이션하여, 해당 컴포넌트의 props가 변경되지 않는 한 재렌더링을 방지합니다. 기본적으로 리액트는 부모 컴포넌트가 렌더링될 때 자식 컴포넌트도 함께 렌더링하지만, React.Memo를 사용하면 props가 동일한 경우 이전의 렌더링 결과를 재사용하게 됩니다.
React.Memo와 useMemo, useCallback의 차이점
React.Memo는 컴포넌트 자체를 메모이제이션하는 반면, useMemo와 useCallback은 값과 함수의 메모이제이션에 중점을 둡니다. React.Memo는 주로 하위 컴포넌트가 동일한 props로 자주 호출될 때 유용하며, 이때 컴포넌트 전체를 재렌더링할 필요가 없는 경우 성능을 크게 향상시킬 수 있습니다.
예제 코드
import React from 'react';
const ChildComponent = React.memo(({ value }) => {
console.log('ChildComponent rendered');
return <div>{value}</div>;
});
const ParentComponent = () => {
const [count, setCount] = useState(0);
return ( <div> <ChildComponent value={count} /> <button onClick={() => setCount(count + 1)}>Increment</button> </div> );
};
위의 예제에서 ChildComponent는 React.Memo로 감싸져 있으므로, count가 변경되지 않는 한 다시 렌더링되지 않습니다. 이를 통해 불필요한 렌더링을 방지하고 성능을 최적화할 수 있습니다.
📌 메모이제이션의 장단점
성능 최적화의 이점
메모이제이션의 가장 큰 장점은 성능 최적화입니다. useMemo, useCallback, 그리고 React.Memo를 적절히 사용하면 불필요한 렌더링과 계산을 방지하여 리소스를 효율적으로 사용할 수 있습니다. 이를 통해 대규모 애플리케이션의 성능을 향상시키고, 사용자 경험을 더욱 부드럽고 빠르게 만들 수 있습니다.
- 불필요한 재계산 방지: 특히 계산 비용이 큰 작업이나 복잡한 연산에서 성능 향상을 기대할 수 있습니다. 예를 들어, 긴 배열을 필터링하거나 무거운 데이터를 처리하는 경우 useMemo를 사용하여 동일한 결과가 필요할 때마다 매번 계산하지 않도록 최적화할 수 있습니다.
- 불필요한 렌더링 방지: useCallback과 React.Memo를 사용하면 하위 컴포넌트에 동일한 props가 전달되었을 때, 다시 렌더링하는 것을 방지할 수 있습니다. 이로 인해 하위 컴포넌트가 복잡하거나 리소스가 많이 소모되는 경우, 성능에 상당한 이점을 제공합니다.
남용 시 문제점
메모이제이션을 잘못 사용하거나 남용하게 되면, 오히려 성능 저하를 일으킬 수 있습니다.
- 불필요한 메모리 사용: 메모이제이션은 내부적으로 값을 저장하는 캐시를 사용하기 때문에, 자주 변하지 않는 값이라면 유용하지만 불필요하게 많은 값을 메모이제이션하게 되면 메모리 자원을 낭비할 수 있습니다. 특히 컴포넌트가 자주 리렌더링되거나 값이 자주 변경되는 경우, 메모이제이션된 값들이 캐시되고, 이를 관리하는 오버헤드가 성능을 저하할 수 있습니다.
- 복잡성 증가: useMemo와 useCallback을 과도하게 사용하면 코드가 불필요하게 복잡해질 수 있습니다. 코드가 간단한 경우에는 메모이제이션을 적용할 필요가 없으며, 오히려 가독성을 해치게 될 수 있습니다. 따라서 메모이제이션은 성능 병목 현상이 실제로 발생하는 경우에만 사용해야 합니다.
📚 결론
리액트에서 제공하는 useMemo, useCallback, 그리고 React.Memo는 성능 최적화에 유용한 도구입니다. 하지만 무조건적으로 사용하는 것보다 실제 성능 병목이 발생하는 부분에서만 적절히 사용하는 것이 중요합니다.
메모이제이션의 적절한 사용 시점
- 비용이 큰 계산: 반복적으로 계산되는 값이 많을 경우 useMemo를 사용하여 계산 비용을 줄일 수 있습니다.
- 함수 전달 최적화: 하위 컴포넌트에 함수 props를 전달할 때 useCallback을 사용하여 불필요한 리렌더링을 방지할 수 있습니다.
- 컴포넌트 재렌더링 방지: React.Memo를 사용하여 동일한 props로 자식 컴포넌트가 재렌더링되지 않도록 할 수 있습니다.
주의할 점
- 메모이제이션은 성능 최적화 도구이지만, 모든 상황에서 필요하지는 않습니다. 성능 이슈가 실제로 발생할 때만 사용하고, 코드 복잡성을 고려해야 합니다.
- 지나친 메모이제이션은 메모리 사용량 증가와 관리 비용을 초래할 수 있으므로, 중요한 부분에만 집중해서 사용해야 합니다.
🔨 참고 자료
공식 문서: https://ko.legacy.reactjs.org/docs/hooks-reference.html
'React' 카테고리의 다른 글
[React-query] 리엑트 쿼리의 Optimistic Update에 대하여 (1) | 2024.12.13 |
---|