함수형 컴포넌트 내에서 선언적으로 메모이제이션(memoization)을 수행하는 Hook이다.
useMemo
를 사용하면 함수의 리턴값을 캐시(cache)하고, 해당 함수의 입력값이 변경되지 않으면 이전에 캐시된 값을 재사용할 수 있다.
따라서 불필요한 연산을 줄이고, 애플리케이션의 성능을 최적화할 수 있다.
컴포넌트의 첫 렌더링 시 실행되고, 이후 리렌더가 될 때마다 캐시된 데이터를 반환해 보여준다.
동일한 값을 반환하는 함수를 반복적으로 호출해야될 때 사용한다.
메모이제이션(memoization)이란 무엇일까?
반복되는 결과를 메모리에 저장 해놓고 다음에 같은 결과가 나올 때 다시 계산할 필요없이 빨리 실행 하는 기법
즉, 한번 연산된 결과를 기억해두고, 다시 동일한 입력이 들어오면 기억해둔 데이터를 반환하는 방법이다.
import { useMemo } from 'react';
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
첫 번째 인자는 계산할 함수이고,
두 번째 인자는 의존성 배열(dependancyArray)을 받는다.
의존성 배열에는 함수를 호출할 때 매번 바뀔 수 있는 값들을 입력하면된다.
그럼 이 값들이 바뀔 때마다 useMemo
에서는 새로운 결과를 계산하고, 값이 바뀌지 않으면 재사용한다.
만약 빈 배열([])을 넘겨주면 맨 처음 컴포넌트가 마운트 되었을 때만 값을 계산하고 이후에는 항상 메모이제이션 된 값을 꺼내와서 사용한다.
import React, { useState, useMemo } from 'react';
function App() {
const [value1, setValue1] = useState(0);
const [value2, setValue2] = useState(0);
const sum = useMemo(() => {
console.log('sum calculated!');
return value1 + value2;
}, [value1, value2]);
return (
<div>
<div>
<button onClick={() => setValue1(value1 + 1)}>Value1 + 1</button>
<button onClick={() => setValue2(value2 + 1)}>Value2 + 1</button>
</div>
<div>
Sum: {sum}
</div>
</div>
);
}
위 코드에서는 value1 과 value2를 더하는 sum 함수를 useMemo()
로 선언했으며,
두 번째 인자에 [value1, value2]
값을 추가하였다.
이제 useMemo
는 [value1, value2]
의 값이 바뀔 때마다 sum 함수를 새로 계산하고,
두 값을 더한 결과를 보여주는 Sum 이라는 컴포넌트를 만들어 사용했다.
이제 버튼을 클릭할 때마다 value1 또는 value2가 변경되는데,
이때 useMemo
의 두 번째 인자 배열 [value1, value2]
를 통해 value1 과 value2가 변경될때마다 sum 함수를 재계산하게 된다.
따라, 콘솔에 "sum calculated!"가 찍히며 Sum 컴포넌트도 매번 새로그려진다.
허나, 버튼을 클릭하지 않는다면?
useMemo
함수가 호출되지 않고 이미 나온 결과값을 메모리에서 꺼내(캐시된 값) 보여준다.
콘솔에도 "sum calculated!"가 찍히지 않는다.
함수를 메모이제이션(memoization)하기 위해 사용되는 Hook이다.
useMemo
와 비슷한 점이 있지만, useCallback
은 함수를 저장하여 매 실행마다 재생성되지 않도록 하는 Hook 이다.
만약, 어떤 리액트 컴포넌트 함수 안에 함수가 선언이 되어 있다면 이 함수는 해당 컴포넌트가 렌더링 될 때마다 새로운 함수가 생성될 것이다.
하지만, useCallback
을 사용한다면, 해당 컴포넌트가 렌더링 되더라도 그 함수가 의존하는 값들이 바뀌지 않는 한 기존 함수를 계속해서 반환한다.(재사용) useMemo
와 유사.
자바스크립트 함수의 동등성, 의존 배열로 함수를 넘길 때 사용하면 좋다. (자세한 내용은 여기)
추가로, 자식 컴포넌트 랜더링의 불필요한 랜더링을 줄이기 위해 React.Memo
와 함께 사용할 수 있다.
useCallback(() => {...}, [dependencies])
첫 번째 인자는 저장할 함수이고,
두 번째 인자는 useCallback 호출의 의존성 배열(dependancyArray)을 받는다.
두 번째 인자로 넘어온 배열 내의 값이 변경될 때까지 저장해놓고, 함수를 재사용할 수 있게 해준다.
function ProductPage({ productId, referrer, theme }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
return (
<div className={theme}>
<ShippingForm onSubmit={handleSubmit} />
</div>
);
}
위는 리액트 공홈에 나와있는 예제이다.(ㅎㅅㅎ)
위의 코드에서 보았을 때 handleSubmit
함수는 의존성 배열이 변경될 때 까지 재 생성되지 않고 유지되며 캐시된다.
useMemo
는 특정 결과값을 재사용 할 때 사용하는 반면,
useCallback
은 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용한다.
함수의 연산량이 많을 때 이전 결과값을 재사용하는 목적으로 useMemo
,
함수가 재생성 되는 것을 방지하기 위한 목적으로 useCallback
.