컴포넌트의 성능을 최적화시킬 수 있는 대표적인 리액트 hooks중 하나이다.
useMemo에서 Memo는 Memoization을 뜻하며,
memoization이란 기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법을 말합니다. memoization을 절적히 적용하면 중복 연산을 피할 수 있기 때문에 메모리를 조금 더 쓰더라도 애플리케이션의 성능을 최적화할 수 있습니다.
컴포넌트 내에 어떤 함수가 값을 리턴하는 데 너무 많은 시간을 소요한다면 매번 재렌더링하는게 부담이 될 수 있다. useMemo를 사용하면 불필요한 재렌더링 현상을 방지 할수 있다.
const memoizedValue = useMemo(() => compute(a, b), [a, b]);
useMemo 의 첫번째 파라미터에는 어떻게 연산할지 정의하는 함수를 넣어주면 되고 두번째 파라미터에는 deps 배열을 넣어주면 되는데, 이 배열 안에 넣은 내용이 바뀌면, 우리가 등록한 함수를 호출해서 값을 연산해주고, 만약에 내용이 바뀌지 않았다면 이전에 연산한 값을 재사용하게 됩니다. 만약 빈 배열([])이라면 맨 처음 컴포넌트가 마운트 되었을때만 값을 계산하고 이후에는 항상 memoization된 값을 꺼내와서 사용합니다.
값을 재활용하기 위해 따로 메모리를 소비해서 저장을 해놓는 것입니다. 그렇기 때문에 불필요한 값을 모두 Memoization해버리면 성능이 안 좋아질 수 있기 때문에 필요할때만 사용하도록 합니다.
useMemo는 특정 결괏값을 재사용할 때 사용하는 반면, useCallback은 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용합니다.
부모 컴포넌트에서 자식 컴포넌트로 함수 props를 넘겨줄때 useMemo는 memoization된 함수를 넘겨주는게 아닌 함수의 리턴 값을 넘겨주기 때문에 함수 props의 불필요한 재렌더링은 막아줄 수 없다. 이 때 사용하는것이 useCallback이다.
const memoizedCallback = useCallback(function, deps);
useCallback은 첫 번째 인자로 넘어온 함수를, 두 번째 인자로 넘어온 배열 형태의 함수 실행 조건의 값이 변경될 때까지 저장해놓고 재사용할 수 있게 해 줍니다.
예를 들어 리액트 컴포넌트 안에 함수가 선언되어있을 때 이 함수는 해당 컴포넌트가 렌더링 될 때마다 새로운 함수가 생성되는데, useCallback을 사용하면 해당 컴포넌트가 렌더링 되더라도 그 함수가 의존하는 값(deps)들이 바뀌지 않는 한 기존 함수를 재사용할 수 있습니다.
일반적으로 소프트웨어의 성능 최적화에는 그에 상응하는 대가(코드가 복잡해지거나 유지보수가 어려워짐)가 따르기 마련입니다. 따라서, useCallback()를 사용하시기 전에 실질적으로 얻을 수 있는 성능 이점이 어느 정도인지 반드시 직접 측정을 해보시고 사용하시기를 권장드립니다.