💡 useMemo
참고영상
https://www.youtube.com/watch?v=e-CnI8Q5RY4&list=PLZ5oZ2KmQEYjwhSxjB_74PoU6pmFzgVMO&index=6
React 로 개발하다 보면 컴포넌트의 성능을 최적화하고 싶은 순간이 찾아온다.
특히 컴포넌트가 자주 리렌더링 되거나, 복잡한 계산을 반복 수행할 때 성능 저하가 발생할 수 있다.
데이터 테이블, 리스트 등에서 수 천 개 이상의 항목을 렌더링 해야 되거나.. 부모 컴포넌트의 상태 변화로 인해 자식 컴포넌트가 불필요하게 재렌더링 되거나.. 이럴 때 useMemo 훅을 사용하면 유용하다.
❓ useMemo 가 뭘까?
useMemo 는 React 훅 중 하나로, 특정 계산의 결과를 메모이제이션(memoization)하여 성능을 최적화하는 데 사용된다. useMemo 에서 Memo 가 memoization 을 뜻한다.
❔ 메모이제이션?
메모이제이션은 동일한 계산을 반복하지 않도록 맨 처음 값을 계산할 때 해당 값을 메모리에 저장해 두고 필요할 때마다 다시 계산하지 않고 저장해 둔 값을 꺼내서 재사용하는 기법이다.
❓ useMemo 구조
const value = useMemo(() => {
return exampleFuntion();
}, []);
- 첫 번째 인자: 메모이제이션 하고자 하는 계산을 수행하는 콜백함수
- (콜백함수가 return 해주는 값 = useMemo 가 return 하는 값)
- 두 번째 인자: 의존성 배열.
- 이 배열에 포함된 값이 변경될 때만 함수를 재실행해서 메모이제이션 된 값을 업데이트하여 다시 메모이제이션 해준다.
- 빈 배열이라면 컴포넌트가 처음 렌더링 될 때만 함수가 실행된다.
❓ 간단한 예제
import React, { useMemo, useState } from "react";
const hardCalculate = (number) => {
console.log('어려운 계산!');
for (let i = 0; i < 999999999; i++) {} // 무거운 연산 시뮬레이션
return number + 10000;
};
const easyCalculate = (number) => {
console.log('쉬운 계산!');
return number + 1;
}
function App() {
const [hardNumber, setHardNumber] = useState(1);
const [easyNumber, setEasyNumber] = useState(1);
// useMemo를 사용하여 어려운 계산의 결과를 메모이제이션
const hardSum = useMemo(() => {
return hardCalculate(hardNumber);
}, [hardNumber]);
const easySum = easyCalculate(easyNumber);
return (
<div className="container">
<h3>어려운 계산기</h3>
<input
type="number"
value={hardNumber}
onChange={(e) => setHardNumber(parseInt(e.target.value))}
/>
<span> + 10000 = {hardSum}</span>
<h3>쉬운 계산기</h3>
<input
type="number"
value={easyNumber}
onChange={(e) => setEasyNumber(parseInt(e.target.value))}
/>
<span> + 1 = {easySum}</span>
</div>
);
}
export default App;
코드 설명
- hardCalculate 함수: 계산 비용이 큰 함수를 정의. 반복문을 사용해서 연산이 오래 걸리도록 시뮬레이션
- easyCalculate 함수: 계산 비용이 적은 함수를 정의.
- useMemo 를 사용해서 hardNumber 가 변경될 때만 hardCalculate 함수가 호출되도록 함.
예제 실행 결과
1. useMemo 사용했을 때
2. useMemo 사용 안 했을 때
easyNumber 를 증가시킬 때는 hardCalculate 가 호출되지 않고, 이미 계산된 hardSum 값을 재사용한다.
정리
- useMemo 를 사용하지 않고 실행했을 땐, 쉬운 계산기도 느리게 작동함
- 근데 useMemo 를 사용하면 hardNumber 값이 바뀔 때만 hardCalculate 를 불러서 hardSum 을 초기화시켜주기 때문에 쉬운 계산기를 증가시킬 때는 이미 메모이제이션 된 값을 사용한다.
- 즉, hardNumber 가 변경될때만 hardCalculate 가 호출되고 hardNum 에 변경사항이 없으면 이미 메모이제이션 된 harSum 값을 재사용한다.
⚠ 주의사항
❔ 타입이 뭘까?
자바스크립트에는 원시타입과 객체 타입이 있다.
원시(Primitive) 타입 | 객체(Object) 타입 (원시 타입을 제외한 모든 것) |
String | Object |
Number | Array |
Boolean | Function |
Null | ... |
Undefined | |
Bigint | |
Symbol |
변수 라는 건 어떤 값을 넣어두는 상자라고 생각하면 되는데,
원시타입의 경우, 어떤 변수에 원시타입의 값을 할당하면 변수라는 상자 안에 바로 값이 들어간다.
비교 연산자로 비교하면 true 가 나옴. 왜냐? 변수라는 상자 안에 있는 값이 동일하기 때문에
근데 객체타입의 경우, 어떤 변수에 객체타입의 값을 할당하면 객체는 너무 크기 때문에 바로 변수라는 상자에 들어가지 않고 어떤 메모리상의 공간에 보관된다. 그리고 변수상자에는 그 객체가 담긴 메모리의 주소가 할당된다.
그래서 같은 객체 값을 갖고 있는 두 변수를 비교하면 false 가 나옴. 왜냐? 변수라는 상자 안에 들어있는 메모리 주소의 값이 다르기 때문에 ( 하나의 메모리에 하나의 객체가 저장됨 )
1. 그럼 만약에, useMemo 를 사용해 준 변수의 값이 객체타입이라면?
useEffect(() => {
console.log('memoizedObject changed:', memoizedObject);
}, [변수]);
지금 useEffect 에 변수의 값이 바뀔 때만 useEffect 가 실행되게 작성해 놨는데..
실제로는 다른 값들이 변경되어도 useEffect 함수가 호출됨.
왜냐? 다른 값들이 변경되었다는 건 컴포넌트가 재렌더링 됐다는 거고 컴포넌트 내부 변수들이 모두 초기화 됐다는 뜻임.
컴포넌트 내부 변수들이 초기화되면 새로운 객체를 다시 할당받게 되니까 메모리 주소가 달라져서 useEffect 관점에서는 아! 저 변수의 값이 변경되었네? 라고 생각하게 되는 거임. (겉으로 보기엔 같아 보여도 다른 객체인 거임)
그래서 객체 타입으로 할당해서 사용하려면 useMemo 를 활용해야 함!
2. 남용하지 말 것
useMemo 는 값을 재활용하기 위해서 따로 메모리를 하나 소비해서 저장해 두는 것이다.
그래서 불필요한 값까지 모두 메모이제이션 해버리면 오히려 성능이 악화될 수 있음.
꼭 필요할 때만 사용하자!
✅ 요약
- useMemo 는 React 의 성능 최적화를 위한 훅으로, 계산된 값을 메모이제이션하여 재계산을 방지한다.
- 첫 번째 인자로 콜백 함수를 받아서 이 함수가 return 하는 값을 메모이제이션 해주고, 두 번째 인자로 의존성 배열을 받아서 배열 안의 값이 변경될 때만 재계산한다.
- 메모이제이션이란, 동일한 계산을 반복하지 않도록 값을 저장해 두고 필요할 때 재사용하는 기법이다.
- useMemo 는 주로 비용이 큰 함수나 복잡한 연산의 결과를 저장하고 싶을 때 사용한다.
- 꼭 필요한 경우에만 사용하고, 불필요한 메모이제이션은 피하자!
'React' 카테고리의 다른 글
[React] JSX 와 state (0) | 2024.09.11 |
---|---|
[React] useCallback 알아보기 (0) | 2024.07.11 |
[React] useRef 알아보기 (0) | 2024.07.11 |
[React] useEffect 알아보기 (0) | 2024.07.11 |
[React] useState 알아보기 (0) | 2024.07.11 |