옛 React 코드에서 자주 만나는 패턴이 모두 새 코드에도 좋은 건 아니야. 무엇이 대체됐고 왜 피해야 하는지 알아두면 유지보수가 쉬워져.
클래스 컴포넌트
초기 React에서는 class Foo extends React.Component와 this.state, this.setState(), 여러 생명주기 메서드로 컴포넌트를 만들었어.
이 방식은 한 기능의 코드가 mount와 update 메서드에 나뉘고, this 바인딩 실수가 잦으며, 상태가 있는 로직을 다른 컴포넌트와 공유하기도 어려웠어. 훅이 등장한 뒤에는 관련 로직을 한곳에 모으고 커스텀 훅으로 나눌 수 있게 됐지. 기존 클래스 코드를 유지보수하는 건 괜찮지만 새 컴포넌트는 보통 훅을 쓰는 함수로 작성해.
HOC
HOC는 컴포넌트를 받아 새 컴포넌트를 돌려주는 함수야. withRouter나 connect(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()처럼 커스텀 훅을 호출하면 같은 로직을 더 평평하게 표현할 수 있어.
여전히 남아 있는 예외
React.memo는 기술적으로 컴포넌트를 감싸지만 로직 공유용 HOC가 아니라 작은 메모이제이션 경계야.Suspense가 자식을 감싸는 것은 컴포지션이지 로직을 주입하는 HOC가 아니야.- 오류 경계는 현재도 React core API 때문에 클래스 컴포넌트로 작성해. Track 5에서 이 예외를 다뤄.