React에서 Memoization: 혹은 내가 앱을 최적화했다고 생각했지만 대부분 그냥 생산적인 느낌만 (But Mostly Just Felt Productive)

발행: (2026년 1월 9일 오전 03:08 GMT+9)
10 min read
원문: Dev.to

I’m ready to translate the article for you, but I need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have it, I’ll translate it into Korean while preserving the original formatting, markdown, and code blocks.

“성능 단계”

작동하도록 만드는 것에 대한 고민을 멈추고, 빠르게 작동하도록 만드는 것에 대해 고민하기 시작합니다. 재렌더링을 마치 빚을 갚아야 할 사람처럼 눈여겨보고, Slack보다 React DevTools를 더 자주 열며, 결국 구글에 검색합니다:

“How to prevent re‑renders in React?”

React는 그 무한한 지혜로 세 가지 마법 같은 단어를 내놓습니다:

  • useMemo
  • useCallback
  • memo

몇 개의 블로그 글을 읽고, YouTube 영상을 1.25배 속도로 시청하고, 코드에 메모이제이션을 양념처럼 뿌린 뒤—짜잔—✨ 최적화 완료

아니면… 그렇게 생각했을 뿐이죠.

그때의 저는—오랫동안—성능 좋은 React 코드를 작성하고 있다고 느꼈지만, 감에 의존하는 것을 그만두고 실제로 React가 몇 가지 상황에서 어떻게 동작하는지 관찰하기로 했습니다. 그 결과는 겸손해질 수밖에 없었습니다: 생산적인 것처럼 보였던 “최적화”가 실제로는 기대한 효과를 전혀 내지 못하고 있었던 겁니다.

오늘은 이 저장소를 실험 playground로 삼아 React에서 메모이제이션에 대한 흔히 오해되는 점들을 함께 살펴보겠습니다:

👉 Repo: (link omitted in original)

혹시 동의하지 않는 부분이 있거나, 공감되는 부분이 있다면 (예의 있게) 댓글로 알려 주세요.

본격적으로 들어가기 전에, 몇 가지 사실에 동의합시다

React 컴포넌트는 다음 경우에 다시 렌더링됩니다:

  1. 내부 상태가 변경될 때
  2. 부모가 다시 렌더링될 때

일부 사람들은 세 번째 규칙을 추가합니다:

  1. props가 변경될 때

개인적으로는 #2가 이미 이를 포함하고 있다고 생각합니다. 동의하지 않으시면 댓글에서 저와 논쟁해 주세요. 언제든 열려 있습니다. 😄

이 두 규칙을 기억하세요—강사가 같은 슬라이드를 반복해서 가리키며 “시험에 나올 거야.” 라고 말하는 것처럼 계속해서 언급될 겁니다.

Source:

오해 #1

“메모이제이션된 값을 컴포넌트에 전달하면 재렌더링이 방지된다”

짧은 답변: 아니요.

긴 답변: 왜 나도 이 생각에 빠졌는지 보여드릴게요.

without-memoized-component 브랜치로 전환해 보세요. 두 개의 컴포넌트를 볼 수 있습니다:

memoized-component.tsx

memoized-component.tsx 코드 내용

(제가 극적으로 가리키고 있다고 상상해 주세요)

App.tsx

app.tsx 코드 내용

(생각에 잠긴 듯 고개를 끄덕이며)

App.tsx에서 중요한 점을 눈여겨 보세요: 함수를 prop으로 전달하기 전에 useCallback을 사용하고 있습니다. 이때의 나는 이미 환호하고 있었죠.

“함수가 메모이제이션됐으니 React가 자식을 재렌더링하지 않을 거야. 나는 성능 천재다.”

이제 count 버튼을 클릭해 보세요:

Rerender mess

자식 컴포넌트가 매번 재렌더링됩니다.

“하지만 함수는 변하지 않았잖아!”

맞아요. 금별 ⭐ 함수 레퍼런스는 안정적입니다.

하지만 규칙을 기억하세요. 규칙 #2 로 돌아가면: 컴포넌트는 부모가 재렌더링될 때 재렌더링됩니다. 부모의 상태가 바뀌었으니 부모가 재렌더링했고, 따라서 자식도 재렌더링된 겁니다.

useCallback이 당신을 실망시킨 것이 아니라—당신의 기대가 실망시킨 겁니다 (나도 마찬가지였어요). 이 상황에서 useCallback은 기본적으로 감정적 지원 역할을 합니다: 기분은 좋아지지만 실제로는 아무것도 막지 못합니다.

“그럼… 어떻게 고치나요?”

쉽습니다. 자식 컴포넌트를 memo 로 감싸고, 앱을 새로 고칩니다(실제로 새로 고치세요). 그리고 다시 버튼을 클릭해 보세요:

Rerender solved

재렌더링이 사라집니다. 이제 우리가 이전에 생각했던 것을 실제로 달성했습니다.

교훈: 컴포넌트를 메모이제이션하지 않은 상태에서 props만 메모이제이션해도 재렌더링에 전혀 영향을 주지 못합니다.

오해 #2

“컴포넌트를 메모이제이션하면 안전해”

memoprops가 변하지 않을 때만 재렌더링을 방지합니다. React는 이를 얕은 비교(shallow comparison) 로 확인합니다. 따라서 다음 중 하나라도 하면 React는 새로운 참조를 감지하고 재렌더링합니다:

  • 인라인 함수를 전달한다
  • 새로 만든 객체를 전달한다
  • 메모이제이션되지 않은 파생 값을 전달한다

그 시점에서 당신의 memo 래퍼는 단지 장식일 뿐입니다.

직접 테스트해 보세요:

  1. App.tsx에서 useCallback을 제거한다
  2. 버튼을 클릭한다
  3. 렌더 카운트가 마치 유산소 운동을 하는 듯 올라가는 것을 확인한다

고통스러운 진실

컴포넌트를 메모이제이션하면서 전달하는 값들을 메모이제이션하지 않는 것은 현관문을 잠그고 창문을 활짝 연 채 두는 것과 같습니다. 겉보기에 안전해 보이지만—안전하지 않다.

요점

언제와 무엇을 메모이제이션 해야 하는지 이해하는 것이 중요합니다. useCallback/useMemo를 사용해 prop 참조를 안정적으로 유지하고, 렌더링 사이에 prop이 실제로 변하지 않는다는 것을 알 때 오직 memo로 컴포넌트를 감싸세요.

메모이제이션은

  • 인지적 비용
  • 유지보수 비용
  • 경우에 따라 성능 비용도 발생할 수 있음

다음 경우에 빛을 발합니다:

  • 재렌더링 비용이 클 때
  • prop이 안정적일 때
  • 실제 문제를 측정했을 때(단순한 느낌이 아니라)

다른 글에서 메모이제이션이 실제로 의미가 있는 시점에 대해 더 깊이 파고들겠습니다.

최종 생각 (고통을 통해 배운 사람으로부터)

오랫동안 나는 올바른 도구를 사용하고 있었기 때문에 성능 좋은 React 코드를 작성하고 있다고 생각했다.

내가 하지 않았던 것은:

  • 동작을 관찰하기
  • 가정을 질문하기
  • React가 다시 렌더링되는 이유를 이해하기

메모이제이션은 마법이 아니다.
그냥 도구일 뿐이다.

그리고 모든 도구와 마찬가지로, 실제로 그것이 무엇을 하는지 알 때 가장 잘 작동한다.

내가 뭔가 틀렸거나 오해한 부분이 있거나, 이 글이 여러분에게 메모이제이션을 다르게 보게 했다면 댓글을 남겨 주세요. 여러분의 생각을 진심으로 듣고 싶어요.

다음 글에서 뵙겠습니다 👋

Back to Blog

관련 글

더 보기 »

React 최적화: 무엇, 언제, 왜

React.memo는 컴포넌트를 메모이제이션합니다. 무엇을 하는가: 함수형 컴포넌트를 감싸며. 자식 컴포넌트의 props가 이전 렌더링과 동일하면, React...