React로 컴포넌트를 최적화하다 보면 React.memo를 자주 사용하게 된다.
그런데 React.memo로 감싼 컴포넌트에는 한 가지 함정이 있다.
아래처럼 익명 화살표 함수를 React.memo로 감싸는 패턴은 흔하다.
const RecipientRow = React.memo(
({ userId, firstName, teamName }: RecipientRowProps) => (
<tr>...</tr>
)
);
여기서 RecipientRow는 변수 이름이지, 함수 자신의 이름이 아니다.
JavaScript에서 함수의 이름은 function.name 프로퍼티로 확인할 수 있다.
const fn = () => {};
console.log(fn.name); // "fn" — 변수명이 추론됨
const memoized = React.memo(() => {});
console.log(memoized.type.name); // "" — memo로 감싸면 추론도 안 됨
React.memo로 감싸는 순간, 변수명 추론도 함께 사라진다.
React DevTools를 열면 컴포넌트 트리에서 이름이 없는 컴포넌트는 Anonymous로 표시된다.
// displayName 없을 때
<Anonymous>
<Anonymous>
// displayName 있을 때
<RecipientRow>
<RecipientRow>
컴포넌트가 몇 개 없을 땐 큰 문제가 아니지만, 실제 서비스에서는 수십 개의 컴포넌트가 중첩되기 때문에 Anonymous만 가득한 트리는 디버깅을 크게 방해한다.
React는 렌더링 중 에러가 발생하면 어떤 컴포넌트에서 발생했는지 출력한다.
// displayName 없을 때
The above error occurred in the <Anonymous> component
// displayName 있을 때
The above error occurred in the <RecipientRow> component
프로덕션 버그를 추적할 때 Anonymous가 찍힌 스택 트레이스는 사실상 단서가 없는 것과 같다.
const RecipientRow = React.memo(
({ userId, firstName, teamName }: RecipientRowProps) => (
<tr>...</tr>
)
);
RecipientRow.displayName = "RecipientRow"; // ✅
displayName은 React가 DevTools와 에러 메시지에서 컴포넌트 이름을 표시할 때 참조하는 프로퍼티다.
공식 문서에서도 디버깅 목적으로 사용한다고 명시하고 있다.
displayName을 별도로 붙이기 싫다면, 기명 함수를 분리해서 memo로 감싸는 방법도 있다.
function RecipientRowBase({ userId, firstName, teamName }: RecipientRowProps) {
return <tr>...</tr>;
}
const RecipientRow = React.memo(RecipientRowBase);
// RecipientRowBase라는 이름이 유지되므로 displayName 불필요
다만 이 경우 DevTools에서는 RecipientRow가 아닌 RecipientRowBase로 표시되므로,
네이밍이 헷갈릴 수 있다는 점은 감안해야 한다.
| 패턴 | DevTools 표시 | displayName 필요 여부 |
|---|---|---|
React.memo(() => ...) | Anonymous | ✅ 필요 |
React.memo(function Foo() {...}) | Foo | 불필요 |
React.memo(FooBase) | FooBase | 불필요 (이름은 원본 함수명) |
React.memo를 익명 함수와 함께 사용한다면, displayName은 선택이 아니라 습관으로 챙겨두는 편이 좋다.
React 공식 문서
displayName 프로퍼티: https://react.dev/reference/react/Component#static-displayname
React.memo: https://react.dev/reference/react/memo
MDN
Function.name 프로퍼티 (변수명 추론 동작 포함): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name