React.memo
React.memo는 컴포넌트의 불필요한 리렌더링을 방지하는 React 최적화 기법입니다. 하지만 “그냥 쓰면 좋은 것”이 아니라, 올바르게 사용하는 기준이 필요하고, 잘못 쓰면 오히려 성능이 더 나빠질 수 있습니다.`
1️⃣ React.memo가 해결하는 진짜 문제
React는 부모가 렌더링되면 자식도 기본적으로 렌더링됩니다.
🔥 문제점
- 부모에 state가 하나만 변경돼도 모든 자식이 리렌더링됨
- 렌더링 비용이 큰 UI(차트, 리스트, 복잡한 컴포넌트)에서 성능 저하
- props가 실제로 바뀌지 않아도 매번 렌더링
✅ React.memo가 제공하는 해결책
- props가 이전 렌더와 동일하면 렌더링 자체를 건너뜀
- 동일한 렌더링 결과를 재사용 → 비용 절감
- 특정 컴포넌트의 렌더링을 "필요할 때만" 일어나도록 제어 가능
즉, React.memo는 "렌더링 비용이 큰 컴포넌트"에 특히 유요한 도구
2️⃣ React.memo 기본 사용 예시
const Child = React.memo(function Child({ count }: { count: number }) {
console.log("Child 렌더링");
return <p>Count: {count}</p>;
});
✔️ props.count가 변경된 경우에만 렌더링
✔️ 부모의 다른 state 변화에는 영향을 받지 않음
3️⃣ 함수 / 객체 / 배열 props 때문에 React.memo가 무용지물 되는 이유
React.memo는 얕은 비교(shallow compare) 를 사용합니다.
즉, 다음과 같은 상황이면 memo가 있어도 매번 리렌더링됩니다.
❌ 새로 만들어진 함수 전달
<Child onClick={() => console.log("hi")}/>
위 함수는 매 렌더링마다 다른 참조값 → memo 무효
✔️ 해결: useCallback
const handleClick = useCallback(() => console.log("hi"), []);
<Child onClick={handleClick} />
❌ 매번 새 배열/객체 생성
<Child list={[1, 2, 3]} />
<Child style={{ color: 'red' }} />
✔️ 해결: useMemo
const list = useMemo(() => [1, 2, 3], []);
const style = useMemo(() => ({ color: 'red' }), []);
4️⃣ React.memo의 사용 기준
✅ 써야하는 경우
✔️ 렌더링 비용이 큰 컴포넌트
- 차트
- 마크다운 렌더러
- 복잡한 리스트 아이템
- 이미지 처리 컴포넌트
✔️ 자주 렌더링되는 부모 아래에 있는 컴포넌트
- 부모가 state를 여러 개 관리
- 부모에서 다양한 이벤트가 발생
- 부모가 context를 사용
✔️ props가 “자주 바뀌지 않는” UI
- static UI 조각
- layout 컴포넌트
🚨 사용하면 안 되는 경우
❌ 렌더링 비용이 거의 없는 단순 UI
- memo의 비교 비용이 오히려 더 큼
❌ props가 매번 바뀌는 컴포넌트
- props로 함수, 배열, 객체가 계속 새로 만들어지는 경우
- 매번 리렌더링되므로 memo가 의미 없음
❌ 부모가 context 값 변경으로 자주 렌더링되는 경우
- memo로도 막기 어려움 → context 구조부터 최적화
❌ 지나친 남용
- 전체 컴포넌트에 “예방적”으로 memo 적용 → 오히려 느려짐
React 공식 권장사항: "렌더링 비용이 큰 컴포넌트에서만 React.memo를 사용하세요."