본문 바로가기
프론트엔드/리액트

React.Memo, useMemo, useCallback은 무엇인가

by 민초의지배자 2025. 6. 10.


1. React의 렌더링과 최적화

React 컴포넌트는 상태(state)나 속성(props)이 변경되면 다시 렌더링된다.
이때 부모 컴포넌트가 렌더링 되면 기본적으로 모든 자식 컴포넌트도 함께 렌더링이 일어나는데, 자식 컴포넌트가 실제로 변경된 값이 없다면 이런 리렌더링은 성능 저하를 유발 할 수 있다. 이때 Memoization을 사용하면 좋다.

 

2. Memoization

메모이제이션이란 수행한 연산의 결과값을 저장해 기억해두고, 동일한 입력이 발생하면 재활용하는 프로그래밍 기법.
적재적소 사용시 중복 연산 피할 수 있기에 어플리케이션의 성능 최적화가 가능 해진다.
useCallback과 useMemo는 메모이제이션 기능을 제공하는 React의 내장 hook으로 퍼포먼스 최적화를 위해 사용 됨.

 


2. React.memo

memo는  React.memo로 함수형 컴포넌트를 감싸서, 해당 컴포넌트의 props가 변경되지 않았을 때는 리렌더가 일어나지 않는다.
1 우선 memo로 감싼 컴포넌트가 렌더될 때, 이전 props와 현재 props를 비교
2. 얕은 비교(shallow comparison)을 수행, 객체나 배열의 경우 참조값 비교
3. props 변경되지 않았다면, React는 이 컴포넌트 렌더링을 건너뛰고 이전에 렌더링된 결과를 재사용.

import React from 'react';

//자식 컴포넌트
const Child = ({ value, onClick }) => {
  console.log('MyChildComponent 렌더링');
  return (
    <div>
      <p>값: {value}</p>
      <button onClick={onClick}>버튼</button>
    </div>
  );
};

// memo로 감싼 자식 컴포넌트
const MemoizedChild = React.memo(({ value, onClick }) => {
  console.log('MemoizedChildComponent 렌더링');
  return (
    <div>
      <p>값: {value}</p>
      <button onClick={onClick}>버튼</button>
    </div>
  );
});

const Parent = () => {
  const [count, setCount] = useState(0);
  const [text, setText] =useState('');

 // ParentComponent가 렌더링될 때마다 새로운 함수가 생성됨
  const handleClick = () => {
    console.log('버튼 클릭!');
return (
    <div>
      <h1>부모 컴포넌트</h1>
      <p>카운트: {count}</p>
      <button onClick={() => setCount(count + 1)}>카운트 증가</button>
      <input type="text" value={text} onChange={(e) => setText(e.target.value)} />

      {/* count가 변경되어 ParentComponent가 렌더링되면 Child도 항상 렌더링됨 */}
      <MyChildComponent value={10} onClick={handleClick} />

      {/*
        MemoizedChildComponent는 value가 10으로 고정되어 변경되지 않지만,
        handleClick 함수는 ParentComponent 렌더링마다 새로운 참조값을 가짐.
        따라서 onClick prop이 변경되었다고 간주하여 MemoizedChildComponent도 재렌더링됨.
        이를 해결하기 위해 useCallback이 필요!
      */}
      <MemoizedChildComponent value={20} onClick={handleClick} />
    </div>
  );
};

export default ParentComponent;

memo: 컴포넌트가 자주 렌더링되지만, 자신의 props가 자주 변경되지 않는 경우. (특히 리스트의 각 아이템 컴포넌트 등)

 

4. useCallback

useCallback은 memorized된 함수를 반환하는 hook으로, 전달된 fn함수를 memoization한다. dependencies에 포함된 값이 변경되지 않는다면 기억해둔 fn함수의 참조 값을 그대로 반환하게 된다. 즉 의존값이 변경되지 않았다면 리렌더를 방지하고 동일한 함수를 재사용하게 한다.

const cachedFn = useCallback(fn, dependencies)
//위에서 예시로 들었던 handleClick은 클릭이 일어 날 때마다 MemoizedChildComponent도 리렌더가 일어나는데 
//useCallback을 사용해 [text]의 값이 그대로면 리렌더가 발생하지 않게 해준다.
const handleClick = useCallback(() => {
    console.log('버튼 클릭!'),[text]);

useCallback: memo로 감싼 자식 컴포넌트에 함수를 props로 전달할 때, 해당 함수가 부모 컴포넌트의 렌더링마다 새로 생성되어 자식 컴포넌트가 불필요하게 재렌더링되는 것을 방지하고자 할 때.

 

5. useMemo

useMemo는 memorized된 값을 반환하는 Hook 함수로, fn 함수의 결과를 dependencies가 변경 될 때마다 캐싱한다.

const cachedValue = useMemo(fn, dependencies)

사용 목적:

  • 복잡한 계산이나 연산이 필요한 값을 불필요하게 다시 계산하는 것을 방지합니다.
  • memo로 감싸진 자식 컴포넌트에 객체나 배열 같은 참조 타입의 prop을 전달할 때 불필요한 재렌더링 방지

6.요약

개념 역할 대상 사용 목적 함께 사용되는 경우
React.memo 컴포넌트 렌더링 최적화 컴포넌트 props가 변경되지 않으면 리렌더 건너뜀 useCallback(props로 함수 전달 시)
useMemo(props로 객체/배열 전달 시 )
useCallback 함수 메모이제이션 함수 불필요한 함수 재생성 방지 memo로 감싼 자식 컴포넌트에 함수를 prop으로 전달 할 때
useMemo 값 메모이제이션 값(변수) 불필요한 값 재계산 방지 memo로 감싼 자식 컴포넌트에 객체/배열을 prop으로 전달 할 때, 복잡한 계산 결과 캐싱

댓글