프론트엔드/React

리액트 훅(Hooks)과 커스텀 훅(Custom Hooks)

학습하는 청년 2024. 6. 17. 13:24

최종 수정 : 2024-06-17

리액트 훅(React Hooks)

2019년 2월 16.8.0 버전에서 리액트 훅이라는 혁신적인 기능이 등장했다. 'use'라는 접두사가 이름에 들어가는 일련의 함수이며, 반드시 함수 컴포넌트에서만 사용해야 한다.

 

# 리액트 훅 종류

용도
컴포넌트 데이터 관리 useMemo
useCallback
useState
useReducer
컴포넌트 생명 주기 대응 useEffect
useLayoutEffect
컴포넌트 메서드 호출 useRef
useImperativeHandle
컴포넌트 간의 정보 공유 useContext

 

# 리액트 훅의 탄생 배경

16.8.0 이전 버전에서 사용자 컴포넌트는 render 메서드를 반드시 구현하는 클래스 기반 컴포넌트 였다. 그런데 클래스에 많은 기능이 숨어 있어 코드가 직관적이지 않았다. 또한, 생명 주기 메서드(lifecycle method)가 많아서 각각의 의미와 정확한 구현 방법을 알기도 어려웠다. 그러면서도 컴포넌트에 구현한 일부 코드를 다른 컴포넌트를 구현할 때 재사용할 마땅한 방법이 없기도 하다.

 

이러한 클래스 컴포넌트를 구현할 때 복잡함과 모호함을 극복할 목적으로 리액트 훅은 만들어졌다. 리액트 훅은 함수 컴포넌트에 다양한 기능을 구현할 수 있게 해준다. 따라서 리액트에서는 함수 컴포넌트 형태로 구현할 것을 권장한다.

 

# 커스텀 훅

리액트 훅은 여러 훅 함수를 조합해 마치 새로운 훅 함수가 있는 것처럼 만들 수 있는데, 이렇게 조합한 새로운 훅 함수를 커스텀 훅(custom hook)이라고 한다. 리액트 훅뿐만 아니라 기존에 제작한 커스텀 훅 함수를 사용해서 만들 수도 있다. 또한, 커스텀 훅 함수는 '훅'이라는 의미를 강조하기 위해 함수 이름에 'use'라는 접두어를 붙여서 만든다.

 

# 리액트 훅 함수의 특징

  1. 여러 번 호출할 수 있다.
  2. 함수 몸통이 아닌 몸통 안 복합 실행문의 { } 안에서 호출할 수 없다.
  3. 비동기 함수를 콜백 함수로 사용할 수 없다.

# 리액트 훅의 기본 원리

리액트 훅을 사용한 개발이란, 몇 가지 적절한 훅 함수를 선택해 컴포넌트의 로직을 개발하는 것이다. 그리고 될 수 있으면 커스텀 훅 함수로 만들어 좀 더 간결한 형태로 재사용할 수 있어야 한다.

 

리액트 훅 함수를 이해하려면 먼저 변수의 유효 범위(scope)에 관해 알아야 한다. 대부분의 프로그래밍 언어에서는 중괄호 { } 안쪽의 범위를 블록 범위(block scope)라고 하고, 블록 범위 안쪽의 변수를 지역 변수(local scope)라고 한다.

 

상태와 캐시

프로그래밍 분야에서 상태(state)란 용어는 변수의 유효 범위와 무관하게 계속 유지(perserve)하는 값을 의미한다. 그런데 상태는 한 번 설정되면 이후로는 값을 변경할 수 없는 '읽기 전용(readonly)' 개념을 가진 불변 상태(immutable state)와 아무 때나 값을 변경할 수 있고 계속 유지하는 가변 상태(mutable state)로 나뉜다.

 

그런데 함수 컴포넌트는 '함수'이므로 블록 범위라는 개념 때문에 상태를 가질 수 없다. 함수 컴포넌트가 상태를 가실 수 있는 유일한 방법은 상태를 담은 변수를 함수 몸통 바깥으로 꺼내어 블록 범위의 영향을 받지 않게 하는 것이다. 이를 전역 변수(global variable)라고 한다.

const global = 1;
export default function UserOrCreate() {
  return <p>{global}</p>
}

 

리액트 훅은 상태를 가질 수 없는 함수 컴포넌트로 하여금 마치 상태를 가진 거서첢 동작할 수 있게 한다. 그리고 이런 개념일 이용하면 캐시(cache)를 전역 변수 형태로 만들어서 구현할 수 있다. 캐시는 데이터나 값을 미리 복사해 놓은 임시 저장소를 의미한다. 원본 데이터에 접근하는 시간이 오래 걸리거나 값을 다시 계산하는 시간을 절약하고 싶을 때 주로 사용한다.

 

캐시와 의존성 목록

리액트 내부에서 관리되는 캐시된 값은 어떤 상황이 일어나면 값을 갱신해 줘야 한다. 리액트 훅에서는 캐시를 갱신하게 하는 요소를 의존성(dependecy)라고 한다. 이러한 의존성으로 구성된 배열을 의존성 목록(dependency list)이라고 한다.

<의존성 목록(dependency list)>
콜백 함수에서 사용되는 변수나 함수의 값이 일정하지 않고 수시로 변할 수 있을 떄, 해당 변수나 함수를 아이템으로 갖는 배열을 의미한다. 리액트에서는 의존성 목록에 있는 아이템 중 하나라도 변화가 있으면 콜백 함수를 새로 고침해 변한 값을 콜백 함수에 반영한다. 만약, 의존성 목록이 빈 배열이라면 콜백 함수는 한 번만 실행된다.

 

# 함수 컴포넌트와 리액트 훅을 사용하는 이유

리액트는 컴포넌트의 속성값이 변경할 때 항상 최신 값이 반영되도록 다시 렌더링해 준다. 그런데 컴포넌트 내부 로직에서 컴포넌트가 다시 렌더링되는 때는 리액트가 탐지하기 어렵다. 이때문에 클래스 기반 컴포넌트는 다양한 메서드를 구현해서 렌더링 여부를 판단할 수 있게 한다.

 

반면에 함수 컴포넌트에 리액트 훅을 사용하면 리액트가 의존송 목록에서 변한 값이 있는지만 판단하면 되므로 다시 렌더링해야 하는 때를 판단하기가 쉽다. 따라서 컴포넌트 개발이 수월해진다.


참고 자료

리액트 모던 웹 개발 with 타입스크립트 (p.254-282)