1. useMemo란
메모이제이션 기법을 기반으로 불 필요한 연산을 최적화하는 리액트 훅이다

✅ 메모이제이션 기법이란?
Memoization : 기억해두기, 메모해두기 라는 뜻

앱에서 반복적으로 수행되는 동일한 연산이
매 번 새롭게 연산 될 수 있다.

메모이제이션 기법은 반복적으로 수행되는
동일한 연산이 있을 때 최초에 실행된 연산의 결과값을
메모리에 보관했다가 다음에 이 연산이 필요할 때
메모리에 저장된 결과 값을 바로 돌려주게 한다.

2. 실습
저번 시간에 만들어두었던 투두 리스트 앱을 활용해보자.
1. 연산 로직 추가
연산 최적화 실습을 위해 기존에 있던 앱에 기능을 추가해보자.
List컴포넌트에서 총 투두 갯수와 완료된 투두, 미완료된 투두를화면으로 보여주는 로직을 만들자.
먼저 해당하는 기능을 수행할 함수를 만드는데,
각각의 갯수를 구하는 연산을 진행하고,
객체로 한 번에 반환하자.
const getAnalyzedData = () => {
const totalCount = todos.length;
const completeCount = todos.filter((todo) => todo.isComplete).length;
const notCompleteCount = totalCount - completeCount;
return {
totalCount,
completeCount,
notCompleteCount,
};
};구조분해할당으로 객체에 담긴 값을 순서대로 받아와주자.
const { totalCount, completeCount, notCompleteCount } = getAnalyzedData();화면에 그대로 렌더링해주자.
<div>
<p>전체: {totalCount}</p>
<p>완료: {completeCount}</p>
<p>미완료: {notCompleteCount}</p>
</div>;
2. 불필요한 연산 확인
추가한 기능에서 완료된 투두의 갯수를 연산하는 식은
투두가 추가될 때마다 점점 더 연산이 오래 걸리는 코드가 될 것이다.
filter 메서드 자체가 배열을 모두 순회하기 때문이다.그래서 가능한 이 함수가 불필요하게 호출되는 경우를 방지해야한다.

현재는 컴포넌트 내에서 바로 호출되고 있기 때문에
List컴포넌트가 리랜더링 될 때마다 불필요하게 연산이 된다.
해당하는 함수가 호출될 때 콘솔에 출력이 되는 코드를
작성해보면 눈으로 확인할 수 있다.

List컴포넌트 내에 검색창에 입력만 해도 해당 함수가입력값이 바뀔 때마다 호출되어 불필요한 연산이 발생함을 알 수 있다.

3. useMemo 사용해보기
불필요한 연산을 막기 위해
useMemo 훅을 사용해보자.이 훅을 호출할 때의 문법은 다음과 같다.
useEffect 문법과 비슷하게 두 가지 인수가 들어가는데,첫 번째 인수로는 특정 조건에만 실행될 동작이 들어갈 콜백 함수,
두 번째 인수로는 조건이 될 의존성 배열이다.
우리는 이 의존성 배열을
deps라 부르는데,deps안의 값이 변경 될 때에만 콜백 함수가 실행되며콜백 함수가 반환하는 값을
useMemo가 그대로 반환하기 때문에변수에 담아 저장할 수 있다.
useMemo(() => {}, []);작성해둔
getAnalyzedData 함수 내부에 있던 코드를콜백 함수 안으로 옮겨주고 기존에 있던
getAnalyzedData는 삭제하자.useMemo(() => {
console.log("getAnalyzedData 함수 호출!");
const totalCount = todos.length;
const completeCount = todos.filter((todo) => todo.isComplete).length;
const notCompleteCount = totalCount - completeCount;
return {
totalCount,
completeCount,
notCompleteCount,
};
}, []);구조 분해 할당으로 받던 값도 삭제하고
useMemo에서 반환하는 값을구조 분해 할당으로 다시 받아주자.
const { totalCount, completeCount, notCompleteCount } = useMemo(() => {
console.log("getAnalyzedData 함수 호출!");
const totalCount = todos.length;
const completeCount = todos.filter((todo) => todo.isComplete).length;
const notCompleteCount = totalCount - completeCount;
return {
totalCount,
completeCount,
notCompleteCount,
};
}, []);마지막으로
deps에 todos를 넣어주면 todos의 값이 변경될 때만로직이 실행되어 불필요한 연산이 발생하는 것을 방지할 수 있다.
const { totalCount, completeCount, notCompleteCount } = useMemo(() => {
console.log("getAnalyzedData 함수 호출!");
const totalCount = todos.length;
const completeCount = todos.filter((todo) => todo.isComplete).length;
const notCompleteCount = totalCount - completeCount;
return {
totalCount,
completeCount,
notCompleteCount,
};
}, [todos]);검색어를 입력해도 더 이상 해당 함수가 호출되지 않는다.

Share article