안녕하세요. IT 엘도라도 에 오신 것을 환영합니다.
글을 쓰는 것은 귀찮지만 다시 찾아보는 것은 더 귀찮습니다.
완전한 나만의 것으로 만들기 위해 지식을 차곡차곡 저장해 보아요.   포스팅 둘러보기 ▼

리액트 (React)

[React] 공식 문서 요약 - Hook 소개

피그브라더 2020. 9. 9. 15:29
 

Introducing Hooks – React

A JavaScript library for building user interfaces

reactjs.org

* React 공식 문서를 꼼꼼히 읽으면서 개인적으로 요약한 내용입니다. 잘못된 내용이 있다면 지적 부탁드립니다.

 

1. Hook 개요

Hook은 함수형 컴포넌트로도 클래스형 컴포넌트의 기능들(상태, 생명주기 메소드 등)을 사용할 수 있도록 하는 새로운 개념으로, React 16.8.0부터 도입이 되었다. 참고로 Hook을 사용하려면 React뿐만 아니라 React DOM을 포함한 모든 패키지도 함께 업데이트해줘야 한다. 이 문서에서는 React가 왜 Hook이라는 것을 새롭게 도입하였는지, 그리고 이것이 애플리케이션의 개발에 어떠한 도움을 주는지에 대해 한 번 설명해볼 것이다. 다음은 2018년 React Conf에서 처음으로 Hook이 소개되는 영상이다.

 

▼ Hook 소개 영상 (React Conf 2018)

 

2. 기존의 코드를 바꿀 필요가 없다.

Hook은 다음과 같은 특징을 지닌다.

 

  • 기존의 코드를 다시 작성할 필요 없이, 특정 컴포넌트에만 부분적으로 Hook을 사용할 수 있다. 필요 없다면 안 써도 된다.
  • 기존 버전과 100% 호환된다. 즉 기존 버전의 호환성을 깨뜨리는 변화가 전혀 없다.
  • React 16.8.0부터 사용할 수 있다.

 

React는 Hook을 도입한다고 해서 클래스형 컴포넌트의 개념을 삭제할 예정은 전혀 없다고 한다. 실제로 페이스북도 기존의 클래스형 컴포넌트들은 거의 건드리지 않고 새로 만드는 컴포넌트들에만 부분적으로 Hook을 사용하고 있다. 이와 같은 Hook의 점진적인 적용 전략에 대해서는 아래에서 설명하도록 한다.

 

Hook은 이미 알고 있는 React의 개념들(props, state, context, refs, 생명주기 등)을 전혀 바꾸지 않는다. 대신에 이러한 개념들을 조금 더 쉽게 사용할 수 있도록 하는 직관적인 API를 제공한다. 또한 이러한 개념들을 엮어서 사용하기 위한 새로운 강력한 방법도 제공한다.

 

3. Hook의 필요성 (Before Hook)

3-1. 상태 관련 로직을 컴포넌트들이 재사용하기 어렵다.

기존의 React는 컴포넌트에 재사용 가능한 로직들을 적용하는 방법을 특별히 제공하지 않았다(EX. Redux 스토어에 컴포넌트를 연결하는 것). 그래서 이전까지는 이러한 문제를 해결하기 위해 Render Props 혹은 고차 컴포넌트(HOC)를 사용해야만 했다. 그러나 이러한 패턴은 컴포넌트를 재구성해야 하며 코드를 이해하기 어렵게 만들었다. 그렇게 만들어진 앱의 컴포넌트 트리를 React 개발자 도구에서 살펴보면 Provider 컴포넌트, Consumer 컴포넌트, HOC 컴포넌트, Render Props, 그리고 다른 추상화된 래퍼 컴포넌트들로 이뤄진 래퍼 지옥(Wrapper Hell)을 볼 가능성이 높았다. 물론 어느 정도는 개발자 도구에서 그러한 래퍼 함수들을 걸러낼 수 있지만, 이는 본질적인 해결책이 아니었다. React는 상태 관련 로직을 컴포넌트들이 공유할 수 있도록 하는 좀 더 나은 기초적인 요소가 필요했던 것이다.

 

Hook은 컴포넌트로부터 상태 관련 로직을 추출하여 추상화시킬 수 있게 하였다. 그리고 이는 독립적으로 테스트하고 재사용하는 것이 가능하였다. 따라서 Hook은 계층의 변화 없이 상태 관련 로직을 컴포넌트들이 공유 및 재사용할 수 있도록 도와준다. 이와 관련한 내용은 '나만의 Hook 만들기' 포스팅을 참조하기 바란다.

 

3-2. 복잡한 컴포넌트는 이해하기 어렵다.

컴포넌트가 복잡해질수록 내부의 상태 관련 로직들 혹은 사이드 이펙트를 유지보수하는 것이 점점 어려워진다. 복잡한 컴포넌트는 각각의 생명주기 메소드가 서로 관련이 없는 로직들을 함께 담고 있거나 서로 다른 생명주기 메소드들이 같은 맥락의 기능을 나눠 가지고 있는 경우가 많다. 이로 인해 버그가 쉽게 발생하고, 코드의 일관성도 쉽게 깨진다. 많은 경우, 이러한 컴포넌트들은 상태 관련 로직들이 곳곳에 존재하하기 때문에 작은 컴포넌트로 나눠 구현하는 것도 쉽지 않다. 그 로직들을 각각 테스트하는 것도 당연히 어렵다. 이러한 이유로 많은 개발자들은 React를 별도의 상태 관리 라이브러리와 함께 사용하는 경향이 있다. 하지만 이러한 라이브러리들은 너무 많은 추상화를 필요로 하고, 여러 파일들 사이에서 왔다 갔다 하도록 만들며, 컴포넌트들의 재사용을 더 어렵게 만든다.

 

Hook을 이용하면, 컴포넌트를 생명주기 메소드 기준이 아닌 각각의 기능들을 기준으로 하여 여러 개의 함수들로 쪼개서 표현할 수 있다. 더불어, 앱의 동작이 조금 더 예측하기 쉽도록 하기 위해 리듀서를 활용하여 컴포넌트의 지역 상태 값을 관리하도록 할 수도 있다. 이와 관련한 내용은 'Effect Hook 사용하기' 포스팅을 참조하기 바란다.

 

3-3. 클래스는 사람과 기계를 모두 혼란스럽게 한다.

클래스는 코드의 재사용성과 코드 구성을 더 어렵게 만들 뿐 아니라, React를 배울 때 큰 진입장벽이 된다. JavaScript에서 this가 어떻게 동작하는지 알아야 하는데, 이것이 일반적인 다른 언어들과는 다르게 동작하여 낯설 수 있다. 또한 이벤트 핸들러를 등록하는 방법도 따로 기억하고 있어야 하는데, 이때 불안정한 몇몇 문법을 사용하지 않으면 코드가 상당히 장황해진다. 이리 하여 사람들은 props 및 state의 개념과 top-down 방식의 데이터 흐름은 쉽게 이해하는 반면 클래스 컴포넌트는 학습하는 데에 꽤 진입장벽이 있다고 느끼는 것이다.

 

/* 추후 보충 학습 필요. */

게다가, React는 5년 동안 지속해 왔으며 추후 5년 뒤까지도 이러한 관련성이 유지되기 바란다. 특별히 템플릿에 제한을 두지 않는다면, Svelte, Angular, Glimmer, 사전 컴파일 컴포넌트 등은 매우 잠재력이 높다. 최근에는 React에서 Prepack을 이용한 컴포넌트 Folding과 관련한 실험을 진행 중인데, 초기 결과가 꽤 긍정적이었다고 한다. 그러나 React는 클래스 컴포넌트가 이러한 최적화 작업을 더욱 어렵게 만드는 의도치 않은 패턴들을 유발하고 있다고 평가한다. 실제로 클래스 컴포넌트는 오늘날 사용하는 몇몇 도구들에서도 많은 문제를 일으킨다. 예를 들어, 클래스는 잘 축소(minimize)되지 않으며, 핫 리로딩을 엉성하고 신뢰할 수 없도록 만든다. 그래서 React는 최적화하기 쉬운 형태의 코드를 작성할 수 있도록 하는 API를 제공하려고 노력한다.

 

이러한 문제를 해결하기 위해, Hook은 클래스 없이도 React의 많은 기능들을 사용할 수 있도록 해준다. 사실 개념적으로 React의 컴포넌트는 함수에 보다 가까운 개념이다. Hook은 React의 정신을 희생하지 않고 함수를 받아들이는 것이다. Hook은 명령형 코드로 해결책을 찾을 수 있게 해주며 복잡한 함수형 혹은 반응형 프로그래밍 기술을 배우도록 요구하지 않는다.

 

4. Hook의 점진적 적용 전략

대부분의 개발자는 새롭게 출시되는 API를 매번 학습하고 사용하는 것에 많은 부담을 느낀다. Hook도 마찬가지이다. 새롭게 출시된 API인 만큼, 어쩌면 이를 공부하는 것에 많은 시간을 투자하는 것보다 그냥 여러 예시들과 튜토리얼이 제공될 때까지 기다리는 것이 더 좋은 선택일 수도 있다. 또한, 개발자들이 React에 새로운 기능을 추가하기 위한 기준이 상당히 높은 것도 사실이다. 그래서 왜 Hook이 필요한가, 즉 동기 부여에 대한 구체적인 내용을 알고 싶어 하는 사람들을 위한 자세한 RFC(Request For Comment)도 제공되고 있다. 이는 구체적인 디자인 의사결정 과정 및 관련된 선행 기술을 다루는 내용들에 관한 추가적인 관점들을 제공한다. 시간이 되면 읽어보기 바란다.

 

앞서 말했듯, React는 클래스 컴포넌트 개념을 삭제할 계획이 전혀 없으며 Hook은 기존 버전과 완전히 호환된다. 따라서 서둘러 Hook을 도입하거나 기존의 코드를 많이 고칠 필요 없이, 필요한 부분에만 Hook을 점진적으로 적용할 수 있다. 이미 존재하는 대규모의 복잡한 클래스형 컴포넌트들을 Hook으로 리팩토링 하는 것은 전혀 권장하지 않는다. 대신, 새로 만들 컴포넌트 혹은 중요하지 않은 컴포넌트에 조금씩 Hook을 사용해보며 연습해보는 것을 권장한다. 차근차근 익숙해지고 점차 확장해 나가는 것이 좋다. 실제로 페이스북도 수만 개의 클래스형 컴포넌트들을 가지고 있지만 이것들을 재작성할 계획은 없다고 한다. 그 대신에 새로운 코드에서 기존 코드와 나란히 Hook을 사용할 계획이라고 한다.