useMemo와 useCallback

April 20, 2023

    React

useCallbakuseMemo는 리액트 앱의 대표적인 성능개선 훅으로 리액트 앱의 과도한 리렌더링을 방지하여 앱의 성능을 향상시킨다. 작동 원리는 리액트 쿼리의 키와 같이 두 함수 모두 의존값을 가지는 배열을 하나 만들어 의존값이 변하지 않을때는 기존에 저장한 값을 사용하고 의존값이 바뀔 때에만 연산을 통해 값을 반환한다.

const memoizedCallback = useCallback(() => { // 함수 로직 }, [dependency]);

useMemo

import React, { useState, useMemo } from 'react'; function calculateExpensiveValue(count) { // 복잡한 연산 수행 return count * 10; // 예시를 위해 간단한 연산 } function App() { const [count, setCount] = useState(0); const [otherValue, setOtherValue] = useState(0); const expensiveValue = useMemo(() => calculateExpensiveValue(count), [count]); //otherValue의 변경으로 컴포넌트가 다시 렌더링 되더라도 count는 계산되지 않고 값이 재사용됨. return ( <div> <p>Expensive Value: {expensiveValue}</p> <button onClick={() => setCount(count + 1)}>Increase Count</button> <button onClick={() => setOtherValue(otherValue + 1)}>Increase Other Value</button> </div> ); } export default App;

원래 컴포넌트 내의 상태(state)가 변하면 컴포넌트가 리렌더링 되면서 expensiveValue가 다시 계산되어야 한다. 하지만 위 예에서는 expensiveValueuseMemocount의 변경에 의존해서만 계산되기 때문에 이전 값을 재사용 하기 때문에 계산이 복잡할수록 useMemo로 성능 향상을 기대할 수 있다.

useCallback

useMemo를 사용하는 상황은 비교적 단순하다. 복잡한 연산을 필요로 하는 작업을 줄이는 방향으로 설계하면 이또한 좋은 방법이 되기 때문이다. 하지만 useCallback은 약간 사정이 다르다. useCallback은 로직의 재활용이 가능하게 해줘서 함수가 속한 컴포넌트가 리렌더링 될 때, 함수의 재선언을 방지해 주는 역할에 그치기 때문에 함수의 재선언 작업정도만 줄여주기 때문이다. 따라서 useCallback을 사용할때에는 몇가지 상황을 고려할 수 있다.

  1. 자식 컴포넌트에 함수를 전달할 때: 부모 컴포넌트가 리렌더링될 때마다 새로운 함수 참조가 생성되어 자식 컴포넌트에 전달되면, 자식 컴포넌트도 불필요하게 리렌더링될 수 있다. 이런 경우 useCallback을 사용하여 함수 참조를 유지하면, 자식 컴포넌트의 불필요한 리렌더링을 방지할 수 있다.

  2. 빈번한 이벤트 처리: 빈번한 이벤트 처리, 예를 들어 스크롤 이벤트나 마우스 이동 이벤트 같은 경우, 매 이벤트 발생마다 새로운 함수가 생성되지 않도록 useCallback을 사용해 함수의 재생성을 줄일 수 있다.

  3. 메모이제이션된 자식 컴포넌트: React.memo를 사용하여 최적화된 자식 컴포넌트가 있고, 이 컴포넌트에 함수를 전달할 경우 useCallback을 사용하여 함수 참조를 유지함으로써, 불필요한 자식 컴포넌트의 리렌더링을 방지할 수 있다.