[React] memo, useCallback을 사용한 렌더링 최적화

2025. 7. 8. 16:27·웹/React

 

문제 상황

오늘은 코코 프로젝트를 개발하며 React 리렌더링을 최적화한 경험에 대해 작성해보려고 한다.

먼저 아래와 같이 렌더링을 확인하기 위한 dev tool을 사용했을 때, 대화 이력을 선택할 때마다 페이지의 모든 컴포넌트가 한꺼번에 리렌더링 되는 현상이 있었다.

 

특정 항목을 선택해도 전체 항목들이 함께 리렌더링 되는 것을 확인할 수 있었다.

 

리렌더링 조건

리렌더링 조건을 찾아보며 왜 이렇게 되는지 그 이유를 찾아 보았다. (이런 기본적인 내용이 생각나지 않았다니..)

그 이유는 페이지 컴포넌트에서 state를 관리하는데, 아마 그 state가 변하면서 하위 컴포넌트들이 모두 리렌더링 된 것이었다.

React에서의 리렌더링 조건은 아래와 같다.

 

  • state가 바뀔 때
  • props가 바뀔 때
  • 부모 컴포넌트가 다시 그려질 때
  • context API에서 값이 바뀔 때 (Provider 내부의 모든 컴포넌트가 리렌더링 된다.)

 

원인 파악

const SessionPage = () => {
  const [selectedSessions, setSelectedSessions] = useState(new Set());
	 
	 // 단일 선택
  const handleSelectSession = (sessionId: number) => {
    const newSelected = new Set(selectedSessions);
    if (newSelected.has(sessionId)) {
      newSelected.delete(sessionId);
    } else {
      newSelected.add(sessionId);
    }
    setSelectedSessions(newSelected);
  };   
    
    // ...
    
    return (
    
	    // ...
	    
	      {allSessions.map((session, index) => {
              const isLastSession = index === allSessions.length - 1;

                  return (
                    <div key={session.sessionId} ref={isLastSession ? lastSessionRef : null}>
                      <SessionItem
                        session={session}
                        isSelected={selectedSessions.has(session.sessionId)}
                        onSelect={handleSelectSession}
                        isSelectionMode={isSelectionMode}
                      />
                    </div>
                  );
          })}
   
    	// ...
}

각 세션 항목은 SessionItem 으로 데이터가 뿌려져 렌더링 되는데, 이때 onSelect 가 바로 페이지 컴포넌트의 state인 selectedSession를 변동시킨다.

따라서 전체 페이지 컴포넌트가 리렌더링 되는 것이다.

 

해결방법: 메모이제이션

React에서는 메모이제이션 방법으로 useCallback, memo, useMemo 가 있다.

useCallback은 함수 참조르 기억,

memo는 컴포넌트 참조를 기억 (자식 컴포넌트 재렌더링 방지),

useMemo는 값(객체)의 참조를 기억한다.

 

1. memo

컴포넌트를 memo로 감싸면 <부모가 리렌더링 되면 자식도 무조건 리렌더링된다>는 조건이 깨진다.

이제 자식의 props가 바뀔 때만 리렌더링 되도록 조건이 바뀐다.

const SessionItem = ({ session, isSelected, onSelect, isSelectionMode }: ISessionItemProps) => {
		/ ... /
};

export default memo(SessionItem);

위와 같이 컴포넌트를 memo로 wrapping 해주었다.

이제 자식의 props (= SessionItem의 props)가 바뀌지 않는 한 리렌더링 되지 않을 것이다.

그러나 그럼에도 아직까지 모든 항목들이 리렌더링 되었다.

2. useCallback

함수는 렌더링마다 새로 생성되며, 참조가 바뀐다.

event handler 함수를 useCallback을 사용해 감싸주면 함수가 재생성 되는 것을 방지하여 참조가 유지되고, 자식의 props가 바뀌었다고 인식하지 않게 되므로, 리렌더링이 되는 것을 막는다고 한다.

따라서 props 중 onSelect가 계속 변하여 발생한 것으로 판단하였고, useCallback 처리 해주어 리렌더링을 최적화 해보았다.

// 단일 선택 (onSelect)
  const handleSelectSession = useCallback((sessionId: number) => {
    setSelectedSessions(prev => {
      const newSelected = new Set(prev);
      if (newSelected.has(sessionId)) {
        newSelected.delete(sessionId);
      } else {
        newSelected.add(sessionId);
      }

      return newSelected;
    });
  }, []);

 

결과

 

 

이제 각 항목을 클릭할 때 모든 페이지가 리렌더링 되지 않게 되었다.

 

'웹 > React' 카테고리의 다른 글

[React 딥다이브🌊] fiber 아키텍처와 동기 렌더링-커밋 프로세스 코드 뜯어보기  (4) 2025.08.03
[React] 좋아요 낙관적 업데이트 적용하기  (1) 2025.07.21
[코드 개선하기] try, catch vs React Query의 onSuccess, onError : 비동기 처리 로직 통일하기  (0) 2025.06.25
[React] 폰트 최적화 + preload 적용해 사용자 경험 개선하기  (0) 2025.06.23
[React, Vite, Vite-bundle-analyzer] CSR에서 초기 로딩 시간 단축하기 2 - 라이브러리 청크 단위로 정적 분리  (0) 2025.06.03
'웹/React' 카테고리의 다른 글
  • [React 딥다이브🌊] fiber 아키텍처와 동기 렌더링-커밋 프로세스 코드 뜯어보기
  • [React] 좋아요 낙관적 업데이트 적용하기
  • [코드 개선하기] try, catch vs React Query의 onSuccess, onError : 비동기 처리 로직 통일하기
  • [React] 폰트 최적화 + preload 적용해 사용자 경험 개선하기
Hyemimi
Hyemimi
배움의 과정에서 느껴지는 소소한 즐거움을 중요시합니다 🌱
  • Hyemimi
    Hyemi.techlog
    Hyemimi
  • 전체
    오늘
    어제
    • 분류 전체보기 (32)
      • 웹 (15)
        • React (10)
        • Next (1)
      • 앱 (0)
        • Flutter (0)
      • 회고 (2)
        • 카카오테크 부트캠프 (4)
      • 언어 (1)
        • JavaScript (0)
        • TypeScript (1)
        • Python (0)
      • CS (3)
      • 알고리즘 (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    비동기
    판교부트캠프
    카카오테크부트캠프
    Vite
    카카오
    오픈소스 컨트리뷰션 아카데미
    OSSCA
    Kakao
    kakaotechbootcamp
    preload
    폰트 최적화
    카테부
    부트캠프
    react
    KTB
    최적화
    부트캠프추천
    CSR
    카테부커뮤니티
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
Hyemimi
[React] memo, useCallback을 사용한 렌더링 최적화
상단으로

티스토리툴바