본문 바로가기
C.W.K.
Stream
Lesson 06 of 07 · published

새 코드에서는 피할 패턴 — HOC, render props, 클래스

~12 min · history, anti-patterns, hooks

Level 0React 입문자
0 XP0/54 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
옛 React 코드에서 자주 만나는 패턴이 모두 새 코드에도 좋은 건 아니야. 무엇이 대체됐고 왜 피해야 하는지 알아두면 유지보수가 쉬워져.

클래스 컴포넌트

초기 React에서는 class Foo extends React.Componentthis.state, this.setState(), 여러 생명주기 메서드로 컴포넌트를 만들었어.

이 방식은 한 기능의 코드가 mount와 update 메서드에 나뉘고, this 바인딩 실수가 잦으며, 상태가 있는 로직을 다른 컴포넌트와 공유하기도 어려웠어. 훅이 등장한 뒤에는 관련 로직을 한곳에 모으고 커스텀 훅으로 나눌 수 있게 됐지. 기존 클래스 코드를 유지보수하는 건 괜찮지만 새 컴포넌트는 보통 훅을 쓰는 함수로 작성해.

HOC

HOC는 컴포넌트를 받아 새 컴포넌트를 돌려주는 함수야. withRouterconnect(mapStateToProps)(Component)처럼 훅이 없던 시절에 상태가 있는 로직을 공유하는 데 쓰였어.

HOC를 여러 겹 감싸면 실제 컴포넌트가 래퍼 안에 묻히고, 서로 주입하는 prop이 충돌해도 알아채기 어렵고, TypeScript 추론과 스택 추적도 복잡해져. 커스텀 훅은 컴포넌트가 무엇을 읽는지 호출 지점에서 바로 보여 주기 때문에 대부분의 HOC 역할을 더 단순하게 대신해.

Render props

Render props는 컴포넌트가 함수를 children이나 다른 prop으로 받아 상태와 함께 호출하는 패턴이야. 예를 들면 <Mouse>{(pos) => <p>{pos.x}, {pos.y}</p>}</Mouse> 같은 모양이야.

이 방식도 동작하지만 JSX가 콜백 안으로 깊어지고 타입이 복잡해지기 쉬워. const pos = useMousePosition()처럼 커스텀 훅을 호출하면 같은 로직을 더 평평하게 표현할 수 있어.

여전히 남아 있는 예외

  1. React.memo는 기술적으로 컴포넌트를 감싸지만 로직 공유용 HOC가 아니라 작은 메모이제이션 경계야.
  2. Suspense가 자식을 감싸는 것은 컴포지션이지 로직을 주입하는 HOC가 아니야.
  3. 오류 경계는 현재도 React core API 때문에 클래스 컴포넌트로 작성해. Track 5에서 이 예외를 다뤄.
오래된 HOC를 걷어낼 때는 주입하던 값을 훅의 반환 값으로 옮겨. 래퍼가 넘겨주던 값을 커스텀 훅이 돌려주게 하고, 원래 컴포넌트가 그 훅을 직접 호출하면 돼. 기능은 남고 불투명한 래퍼 계층만 사라져.

Code

같은 기능을 render prop과 커스텀 훅으로 비교하기·tsx
// 2018 — render props
class Mouse extends React.Component<{ children: (p: {x:number;y:number}) => React.ReactNode }, {x:number;y:number}> {
  state = { x: 0, y: 0 };
  handle = (e: MouseEvent) => this.setState({ x: e.clientX, y: e.clientY });
  componentDidMount() { window.addEventListener("mousemove", this.handle); }
  componentWillUnmount() { window.removeEventListener("mousemove", this.handle); }
  render() { return this.props.children(this.state); }
}
// 사용 — 콜백 안의 JSX가 태그 안에.
<Mouse>{(pos) => <p>{pos.x}, {pos.y}</p>}</Mouse>

// 2026 — 커스텀 훅 (Track 3 lesson 4가 제대로 짓는 법)
import { useEffect, useState } from "react";
function useMousePosition() {
  const [pos, setPos] = useState({ x: 0, y: 0 });
  useEffect(() => {
    const handle = (e: MouseEvent) => setPos({ x: e.clientX, y: e.clientY });
    window.addEventListener("mousemove", handle);
    return () => window.removeEventListener("mousemove", handle);
  }, []);
  return pos;
}
function Tracker() {
  const pos = useMousePosition();
  return <p>{pos.x}, {pos.y}</p>;
}

External links

Exercise

실제 저장소에서 withRouter나 connect(mapStateToProps) 같은 HOC를 하나 찾아 커스텀 훅으로 바꾸는 설계를 적어 봐. HOC가 주입하던 값, 훅이 반환할 값, 원래 컴포넌트가 훅을 호출할 위치를 차례로 정리해.
Hint
래퍼가 prop으로 넣던 값을 커스텀 훅이 반환하게 만들면 돼. 기능은 유지하면서 원래 컴포넌트가 값을 어디서 읽는지 직접 보여 주는 게 목표야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.