
리액트 훅(React Hooks) 등장의 역사적 배경
핵심 요약
리액트 훅은 2013년부터 2018년까지의 5년간 축적된 문제점들을 해결하기 위해 등장했다. 클래스 컴포넌트의 복잡성, 코드 재사용 문제, JavaScript의 this
바인딩 혼란, 그리고 “래퍼 지옥(Wrapper Hell)” 등이 주요 동기였다. 2019년 2월 6일 React 16.8과 함께 정식 출시되어 함수형 컴포넌트가 클래스 컴포넌트의 모든 기능을 사용할 수 있게 되었다12.
1. 리액트 초기 역사 (2013-2016): 컴포넌트 작성 방식의 변천
1.1 createClass 시대 (2013-2015)
리액트가 2013년 JSConf에서 공개되었을 때는 React.createClass()
방식을 사용했다34. 이는 JavaScript ES5에 클래스 문법이 없었기 때문이다.
var ExampleComponent = React.createClass({
getInitialState: function() {
return { count: 0 };
},
mixins: [SomeMixin],
render: function() {
return <div>{this.state.count}</div>;
}
});
- 의존성 추적 어려움: 어떤 mixin에서 메서드가 오는지 파악 곤란
- 네임스페이스 충돌: 여러 mixin이 같은 메서드명 정의 시 오류 발생6
- 암묵적 의존성: mixin 간 숨겨진 결합도
1.2 ES6 클래스 전환 (2015-2016)
JavaScript ES6(ES2015)가 2015년에 출시되면서 클래스 문법이 도입되었다78. React는 2016년경 ES6 클래스 컴포넌트를 표준으로 채택했다910.
class ExampleComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
this.handleClick = this.handleClick.bind(this); // this 바인딩 필요
}
handleClick() {
this.setState({ count: this.state.count + 1 });
}
render() {
return <button onClick={this.handleClick}>{this.state.count}</button>;
}
}
2. 클래스 컴포넌트의 근본적 문제들
2.1 JavaScript의 this
바인딩 문제
클래스 컴포넌트 최대 난제는 **이벤트 핸들러에서 this
가 undefined
**가 되는 것이었다111213.
// 문제 코드
<button onClick={this.handleClick}>Click</button>
// this.handleClick이 호출될 때 this가 undefined
// 해결 방법들
this.handleClick = this.handleClick.bind(this); // 생성자에서 바인딩
<button onClick={() => this.handleClick()}>Click</button> // 화살표 함수
이는 JavaScript의 기본 특성으로, 메서드가 객체에서 분리되어 호출되면 this
컨텍스트를 잃기 때문이다1314.
2.2 생명주기 메서드의 로직 분산 문제
관련 없는 로직이 하나의 생명주기 메서드에 섞이고, 연관된 로직은 여러 메서드에 흩어지는 문제가 있었다1:
componentDidMount() {
// 데이터 페칭
this.fetchUserData();
// 이벤트 리스너 등록
window.addEventListener('resize', this.handleResize);
// 타이머 설정
this.timer = setInterval(this.updateClock, 1000);
}
componentWillUnmount() {
// 정리 작업들이 별도 메서드에 분산
window.removeEventListener('resize', this.handleResize);
clearInterval(this.timer);
}
2.3 컴포넌트 간 로직 공유의 복잡성
클래스 컴포넌트에서 상태 있는 로직을 공유하려면 HOC(Higher-Order Components)나 Render Props 패턴을 사용해야 했다115.
HOC 패턴의 문제점
// 여러 HOC 중첩 시 "래퍼 지옥" 발생
const EnhancedComponent = withAuth(
withTheme(
withLoading(
withUserData(MyComponent)
)
)
);
Render Props의 문제점
<DataProvider>
{data => (
<ThemeProvider>
{theme => (
<AuthProvider>
{auth => (
<MyComponent data={data} theme={theme} auth={auth} />
)}
</AuthProvider>
)}
</ThemeProvider>
)}
</DataProvider>
```
이런 패턴들은 **"래퍼 지옥(Wrapper Hell)"**을 만들어 DevTools에서 컴포넌트 트리가 복잡해지고 디버깅이 어려워졌다[^1][^16][^17].
## 3. 훅 도입의 직접적 동기 (2018년)
### 3.1 React팀의 공식 동기 발표
**2018년 React Conf에서 Dan Abramov가 발표**한 Hooks 도입 동기는 3가지였다[^1][^18]:
1. **컴포넌트 간 상태 로직 재사용의 어려움**
2. **복잡한 컴포넌트의 이해 어려움**
3. **클래스가 사람과 기계 모두에게 혼란스러움**
### 3.2 성능 및 최적화 관점
클래스 컴포넌트는 **미래의 React 최적화 기법과 호환성 문제**가 있었다[^1]:
- **컴포넌트 폴딩(Component Folding)** 최적화에서 더 느린 경로로 빠짐
- **Ahead-of-Time 컴파일**에서 제약 사항
- **코드 압축(Minification)**에서 비효율적
### 3.3 학습 곡선과 개발자 경험
클래스 컴포넌트는 **React 학습의 큰 장벽**이었다[^1][^19]:
- JavaScript `this` 개념 이해 필요
- 생명주기 메서드 암기
- 바인딩 문법의 복잡성
- 경험 많은 개발자들 사이에서도 함수형 vs 클래스형 선택에 논란
## 4. 훅의 해결책과 출시 (2019년)
### 4.1 훅이 제공한 해결책
```javascript
// 클래스 컴포넌트 (Before)
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ count: this.state.count + 1 });
}
render() {
return <button onClick={this.handleClick}>{this.state.count}</button>;
}
}
// 함수형 컴포넌트 + 훅 (After)
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
4.2 커스텀 훅으로 로직 재사용
// 커스텀 훅으로 깔끔한 로직 공유
function useCounter(initialValue = 0) {
const [count, setCount] = useState(initialValue);
const increment = () => setCount(c => c + 1);
const decrement = () => setCount(c => c - 1);
return { count, increment, decrement };
}
// 사용
function MyComponent() {
const { count, increment, decrement } = useCounter(10);
return (
<div>
<span>{count}</span>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
4.3 정식 출시
2019년 2월 6일 React 16.8.0과 함께 안정화된 훅이 출시되었다216. 이는 React 역사상 가장 중요한 전환점 중 하나로 평가받는다17.
5. 훅 도입의 역사적 의의
5.1 패러다임 변화
훅은 단순한 새 기능이 아니라 React 철학의 진화를 보여준다18:
- 클래스 없이도 완전한 컴포넌트 작성 가능
- 함수형 프로그래밍 패러다임 강화
- 컴포넌트 로직의 선언적 표현
5.2 생태계 영향
훅 출시 이후 React 생태계 전반이 함수형 컴포넌트 중심으로 재편되었다19:
- 새로운 라이브러리들이 훅 기반으로 설계
- 기존 HOC/Render Props 패턴에서 커스텀 훅으로 전환
- React 공식 문서도 함수형 컴포넌트 우선으로 개편
결론
리액트 훅은 5년간의 실전 경험에서 나온 문제점들을 체계적으로 해결한 혁신이다. 클래스 컴포넌트의 복잡성, 로직 재사용의 어려움, JavaScript this
의 혼란, 래퍼 지옥 등 개발자들이 실제로 겪던 고충을 해결했다. 2019년 정식 출시 이후 React는 더욱 직관적이고 재사용 가능한 방향으로 발전했으며, 이는 현대 웹 개발 패러다임에 큰 영향을 미치고 있다.
Footnotes
-
https://ko.legacy.reactjs.org/blog/2019/02/06/react-v16.8.0.html ↩ ↩2
-
https://blog.risingstack.com/the-history-of-react-js-on-a-timeline/ ↩
-
https://www.geeksforgeeks.org/reactjs/history-and-evolution-of-react/ ↩
-
https://ko.legacy.reactjs.org/blog/2016/07/13/mixins-considered-harmful.html ↩
-
https://www.newmediacampaigns.com/blog/refactoring-react-components-to-es6-classes ↩
-
https://typeofnan.dev/how-to-fix-undefined-this-state-in-react-class-components/ ↩
-
https://www.basefactor.com/react-class-components-pitfalls/ ↩
-
https://exploringreact.com/2020/11/28/why-do-we-need-to-use-bind-for-events-in-class-based-components/ ↩ ↩2
-
https://stackoverflow.com/questions/69267661/why-my-class-method-works-in-react-without-explicitly-binding-it-to-this ↩
-
https://dev.to/ryansolid/the-react-hooks-announcement-in-retrospect-2-years-later-18lm ↩
-
https://dev.to/colocodes/react-class-components-vs-function-components-23m6/comments ↩