1. 소개
- React 앱을 개발하면서 성능 최적화는 항상 고려해야 할 중요한 측면임. 이때 useMemo 훅은 메모이제이션을 통해 성능을 향상시킬 수 있는 강력한 Hook임
- 이번 글에서는 React의 useMemo 훅에 대해 알아보고, 그 특징과 장점에 대해 시작해보겠음
2. 특징
- 메모이제이션: useMemo 훅은 이전에 계산된 값을 기억하여 동일한 계산을 반복하지 않고 이전에 계산된 값을 재사용하고, 이를 통해 불필요한 계산을 방지하여 성능을 향상시킴
- 의존성 배열: useMemo 훅은 두 번째 매개변수로 의존성 배열을 받고, 이 배열에 포함된 값들이 변경될 때에만 메모이제이션된 값이 다시 계산됨
3. 장점
- 성능 향상: useMemo를 사용하면 렌더링 시간을 줄일 수 있음! 특히 계산 비용이 높거나 자주 변경되지 않는 값들을 메모이제이션하여 불필요한 계산을 최소화할 수 있음
- 코드 가독성: useMemo를 사용하면 계산된 값을 쉽게 추적할 수 있음, 이전에 계산된 값을 재사용하는 것이 명시적으로 표현되므로 코드의 의도를 명확하게 전달가능함
- 렌더링 최적화: useMemo를 적절히 활용하면 불필요한 렌더링을 방지할 수 있고, 메모이제이션된 값이 변경되지 않는 한 해당 값이 사용된 컴포넌트는 다시 렌더링되지 않음
4. 예시코드
useMemo를 사용하기전 코드
import { useMemo, useState } from "react";
import "./App.css";
const hardCalculate = (number) => {
console.log("어려움 시간이 오래걸림 쓸데없는 반복을 돌기때문");
// 스테이트에 값을 게속 넣고 비교하기때문에 렌더링을 반복문 만큼 게속하게되고
// 즉각적으로 값을 변화시키는게 아니기 때문에 딜레이 값이 있음
for (let i = 0; i < 9999999; i++) {
return number + 10000;
}
};
const easyCalculate = (number) => {
// 마찬가지로 쉬운 계산기를 만들어도 App컴포넌트 안에 있어서
// 전체적으로 렌더링이 되기때문에 hardCalculate도 동작을 해서
// 쉬운계산기여도 딜레이를 가지게됨 이때 useMemo를 사용하면 좋음
console.log("쉬움");
return number + 1;
};
function App() {
const [hardNumber, setHardNumber] = useState(1);
const [easyNumber, setEasyNumber] = useState(1);
const hardSum = hardCalculate(hardNumber);
const easySum = easyCalculate(easyNumber);
return (
<div>
<h3>어려운 계산기</h3>
<input
type="number"
value={hardNumber}
onChange={(e) => setHardNumber(e.target.value)}
/>
<span> + 10000 = {hardSum}</span>
<h3>쉬운 계산기</h3>
<input
type="number"
value={easyNumber}
onChange={(e) => setEasyNumber(e.target.value)}
/>
<span> + 10000 = {easySum}</span>
</div>
);
}
export default App;
- useMemo를 사용하기전에는 위와같이 불필요한 렌더링을 해서 hardCalculate, easyCalculate 함수를 실행하면 App 컴포넌트가 전체 렌더링이 되면서 불필요한값이 콘솔에 찍히게됨
2. useMemo를 사용후
const hardSum = useMemo(() => {
// use Memo는 두가지의 인자를 받음, 콜백함수, 의존성배열
// 아래와같은 코드로 작성하면 hardNumber가 변경이 될때만
// hardCalculate 함수가 돌기때문에 불필요한 렌더링을 방지할수있고
// hardNumber가 변경되지않으면 이전에 가지고있던 값을 메모리에 저장해두었다가 사용함
return hardCalculate(hardNumber);
}, [hardNumber]);
- useMemo를 사용한 후 에는 1번과 같은 불필요한 렌더링을 하지않고 사용하는 값만 렌더링하고, 의존성 배열안에 있는값이 변화하지 않으면 렌더링을 하지않고, 그전에 메모리에 저장된 값을 보여줌
5. 객체타입 사용시 useMemo
- 원시타입 사용시 useEffect를 사용하면 아래 예시코드와 같이 해당된 원시타입의 변수에 대해서만 렌더링이 발생됨
- 하지만 객체타입으로 useEffect 사용시 전체컴포넌트가 렌더링이 발생하는데 그 이유는 자바스크립트의 타입에 따라 렌더링이 되기 때문임, 원시타입은 변수 그대로의 값을 비교하지만 객체타입의 경우 객체안의 변수를 그대로 저장하는것이 아닌 메모리에 값이 할당이되고, 메모리의 주소가 객체안에 할딩이됨
- 그래서 같은 원시타입을 비교하면 true가 나오지만
- 같은 객체타입을 비교하면 메모리안에 할당된 주소가 다르기 때문에 같은변수처럼 보이더라도 false가 나오게됨
- 이럴때 객체타입은 useMemo를 사용하여 불필요한 렌더링을 줄임
import React, { useEffect, useMemo, useState } from "react";
export default function App() {
const [number, setNumber] = useState(0);
const [isKoran, setKorea] = useState(true);
const location = useMemo(() => {
// 이렇게 useMemo를 사용하여 객체타입은 불필요한 렌더링을 방지하면
// 햄최면 Input을 클릭해도 객체타입은 렌더링을 하지않게됨
return {
country: isKoran ? "한국" : "외국",
};
}, []);
useEffect(() => {
console.log("useEffect 호출함");
// 의존성배열에 원시타입이아닌 객체타입이 들어가면
// 햄최몇의 input값이 바뀌어도 렌더링이되어 콘솔이 찍히게됨
// 그 이유는 자바스크립트가 동작하는 원리때문인데
// 원시타입의 경우 값을 그대로 가져오지만
// 객체타입의 경우 메모리값이 할당되고 그 메모리안에 할당이되고
// 그객체안의 변수에는 메모리의 값이아닌 메모리의 주소가 할당됨
//그예로 같은 원시데이터를 비교하면 true가 나오지만
// 같은 객체타입을 비교하면 false가 나옴
// 그이유는 객체안의 변수에는 메모리의 주소가 다르기때문임
}, [location]);
return (
<div>
<h2>햄최몇?</h2>
<input
value={number}
type="number"
onChange={(e) => {
setNumber(e.target.value);
}}
/>
<hr />
<h2>어디사냐?</h2>
<p>여기살고 있는데 왜? 뭐? {location.country}</p>
<button onClick={() => setKorea(!isKoran)}> 아니그냥</button>
</div>
);
}
6. 개념 추가
ㄱ. Call by value (값에 의한 호출):
- 이 방식은 함수에 인자를 전달할 때 값 자체를 복사하여 전달합니다. 함수 내부에서 인자의 값이 변경되어도 호출된 쪽에는 영향을 주지 않습니다.
- 호출하는 변수의 값만을 복사하여 함수 내부로 전달되기 때문에, 함수 내부에서 해당 값을 변경하더라도 호출된 곳의 변수 값에는 영향을 주지 않습니다.
- 대부분의 언어에서 함수의 인자 전달 방식이 이 방식으로 이루어집니다.
ㄴ. Call by reference (참조에 의한 호출)
- 이 방식은 함수에 인자를 전달할 때 변수의 참조(메모리 주소)를 전달합니다. 따라서 함수 내부에서 해당 참조를 통해 변수 값을 직접 변경할 수 있음.
- 함수에 인자로 변수를 전달할 때, 변수의 메모리 주소가 전달되므로 함수 내에서 변수 값을 변경하면 호출한 곳에서도 변경된 값을 확인할 수 있습니다.
- 이 방식은 몇몇 언어에서 사용되며, 일반적으로 포인터나 참조를 이용하여 구현됩니다.
'Frontend > React' 카테고리의 다른 글
"React에서의 상태 관리" : Custom Hook vs. Context API (2) | 2024.02.04 |
---|