리액트 공식 문서를 참고한 정리 내용 (25.08 기준)
리렌더링 간에 함수 정의를 캐싱해 준다.
const cachedFn = useCallback(fn, dependencies)
함수 정의를 캐싱하려면 컴포넌트 최상단에서 useCallback을 호출해야 한다.
import { useCallback } from 'react';
export default function ProductPage({ productId, referrer, theme }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
fn 그대로를 반환해준다.dependencies가 이전과 같으면 “기존 함수 그대로 반환(새로 안 만듦)”한다.dependencies가 바뀌면, 새로 만든 fn을 반환하고 그걸 이후에도 재사용할 수 있게 캐싱한다.👉 불필요하게 함수가 매번 새로 만들어지지 않도록 React가 기억해둔다.
dependencies(의존성 배열)fn 안에서 쓰이는 props, state, 컴포넌트 내부 변수·함수들이 의존성에 들어가야 한다.[dep1, dep2, dep3]처럼 인라인으로 작성해야 한다.Object.is 비교 알고리즘을 이용해 각 의존성을 이전 값과 비교해, 달라졌는지 확인한다.👉 의존성 배열은 “이 값들이 변하면 캐싱된 함수도 새로 만들어라”라는 체크리스트
fn 함수를 그대로 반환한다.fn 함수를 반환하고, 변한 경우에는 현재 렌더링 중에 전달한 fn 함수를 그대로 반환한다. useCallback은 Hook이므로 컴포넌트의 최상위 레벨 또는 커스텀 Hook에서만 호출할 수 있다.useCallback을 의존하지 말고, 경우에 따라서는 state나 ref 같은 다른 방법이 더 적절할 수 있다.useCallback과 useMemo는 어떤 연관이 있나요?useMemo과 useCallback은 모두 자식 컴포넌트를 최적할 때 유용하다. 무언가를 전달할 때 memoization(다른 말로는 캐싱)을 할 수 있도록 해준다.
import { useMemo, useCallback } from 'react';
function ProductPage({ productId, referrer }) {
const product = useData('/product/' + productId);
const requirements = useMemo(() => { // 함수를 호출하고 그 결과를 캐싱합니다.
return computeRequirements(product);
}, [product]);
const handleSubmit = useCallback((orderDetails) => { // 함수 자체를 캐싱합니다.
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
return (
<div className={theme}>
<ShippingForm requirements={requirements} onSubmit={handleSubmit} />
</div>
);
}
useMemo는 호출한 함수의 결과값을 캐싱한다. 이는 불필요하게 컴포넌트를 리렌더링하지 않고 객체를 넘겨줄 수 있도록 해준다. 필요할 때, React는 렌더링 중에 넘겨주었던 함수를 호출하여 결과를 계산한다.useCallback은 함수 자체를 캐시한다. useMemo와 달리, 전달한 함수를 호출하지 않고, 전달한 함수를 캐싱해서 배열의 값이 변하지 않으면, 함수 자체가 변하지 않도록 한다.