Hook은 리액트의 함수형 컴포넌트에서 상태(state)와 생명주기 기능(lifecycle features)을 사용할 수 있게 해주는 함수이다.
리액트의 컴포넌트는 크게 클래스형과 함수형으로 나눠진다.
Hook 도입 전
클래스형 컴포넌트의 문제점
render props
나 HOC(고차 컴포넌트)
패턴을 통해 해결할 수 있으나, 이로 인해 코드 추적이 어려워지고, 복잡한 구조로 인해 wrapper hell에 빠질 수 있다.리액트 16.8버전부터 Hook이 도입되면서, 함수형 컴포넌트에서도 상태와 생명주기 기능을 사용할 수 있게 되었다.
예를 들어, useState
를 사용하면 클래스를 사용하지 않고도 상태를 가질 수 있다.
Hook 덕분에 함수형 컴포넌트에서 상태값 접근 및 생명주기 기능을 보다 쉽게 구현할 수 있으며, 클래스형 컴포넌트의 복잡성을 피할 수 있게 되었다.
컴포넌트로부터 상태 관련 로직을 추상화
상태 로직의 계층적 중첩 없이 재사용 가능
생명주기 메서드 대신 작은 함수의 묶음으로 구성
1) 최상위 에서만 훅을 호출해야 한다.
반복문, 조건문, 중첩된 함수 내에서 사용 불가
왜 훅의 호출 순서가 같아야 하는 걸까?
리액트가 상태값을 구분할 수 있는 유일한 정보는 Hook이 사용된 순서이기 때문이다. 예를 들어, 반복문 안에서 Hook을 호출하면, 반복문의 조건에 따라 호출 순서가 달라질 수 있어 오류가 발생할 수 있다.
조건문이나 반복문에서 상태 로직을 사용하고 싶다면, useEffect 안에 넣어 사용하면 된다.
2) React 함수 컴포넌트 내에서만 Hook을 호출해야 한다
useEffect를 이용하여 특정 조건에 따라 사이드 이펙트를 실행한 예시
function ExampleComponent() { const [count, setCount] = useState(0); const [isEven, setIsEven] = useState(true); ㅤ // count 값이 변경될 때마다 isEven 상태를 업데이트 useEffect(() => { if (count % 2 === 0) { setIsEven(true); } else { setIsEven(false); } }, [count]); // count가 변경될 때마다 실행됨 . . . }
구분 | 일반 JavaScript 함수 | React 훅 | React 컴포넌트 |
---|---|---|---|
주 목적 | 특정 로직 캡슐화 및 재사용 | React 상태 관리 및 생명주기 관리 | UI를 정의하고 화면에 렌더링 |
사용 환경 | 어디서나 사용 가능 (React, Node.js 등) | React 컴포넌트 내부에서만 사용 가능 | React 애플리케이션에서 사용 |
React 종속성 | 독립적 | React에 종속적 | React에 종속적 |
상태 관리 | 상태를 직접 관리하지 않음 | React 상태를 간단히 관리 | 상태 및 Props를 활용하여 UI를 동적으로 업데이트 |
형태 | 일반 함수나 화살표 함수 | use 로 시작하는 React 전용 함수 | 함수형 컴포넌트 (function Component() {} ) 또는 클래스형 컴포넌트 (class Component extends React.Component ) |
입력 및 출력 | 입력값을 받아 결과를 반환 | 상태(State) 및 생명주기 이벤트를 관리 | Props를 입력받아 React 엘리먼트를 반환 |
의미적 역할 | 로직 중심의 기능 제공 | React 컴포넌트 내부 동작을 위한 도구 | 화면에 UI를 정의하고 렌더링 |
일반 JavaScript 함수:
React 훅:
React 컴포넌트:
커스텀 훅(Custom Hook)은 리액트에서 제공하는 기본 훅(useState, useEffect 등)을 조합하여 사용자가 직접 만드는 훅이다. 커스텀 훅을 사용하면 여러 컴포넌트에서 반복적으로 사용하는 로직을 재사용할 수 있다.
리액트 애플리케이션을 개발하다 보면, 여러 컴포넌트에서 동일한 로직이 반복되는 경우가 많다. 이때 커스텀 훅을 사용하면 다음과 같은 이점이 있다:
1. 코드의 재사용성
동일한 로직을 여러 컴포넌트에서 반복해서 작성할 필요 없이, 커스텀 훅으로 만들어두면 재사용할 수 있다.
2. 코드의 가독성 및 유지보수성 향상
중복된 코드가 사라지고, 컴포넌트는 그 컴포넌트의 역할에 집중할 수 있게 되어 코드가 더 깔끔해지고 이해하기 쉬워진다.
3. 로직의 분리
상태 관리나 비즈니스 로직을 컴포넌트에서 분리하여, 커스텀 훅에 넣음으로써 컴포넌트는 UI와 관련된 로직에만 집중할 수 있다.
1. 복잡한 로직을 단순하게 관리
복잡한 비즈니스 로직이나 상태 관리 로직을 커스텀 훅으로 분리하면, 컴포넌트가 훨씬 단순해진다.
2. 다양한 컴포넌트에서 재사용 가능
한 번 만들어둔 커스텀 훅을 여러 컴포넌트에서 재사용할 수 있어, 코드의 일관성을 유지할 수 있다.
3. 컴포넌트 간에 상태와 로직 공유
여러 컴포넌트가 동일한 상태나 로직을 공유해야 할 때, 커스텀 훅을 사용하면 상태와 로직을 쉽게 공유할 수 있다.
4. 독립적인 테스트 가능
커스텀 훅은 독립적으로 테스트할 수 있어, 로직에 대한 단위 테스트 작성이 용이해진다.
예를 들어, 사용자 입력을 처리하는 로직이 여러 컴포넌트에 필요할 때 useInput
이라는 커스텀 훅을 만들 수 있다. 이 훅을 사용하면 각 컴포넌트에서 입력 처리 로직을 중복해서 작성하지 않고, 훅을 호출하여 간편하게 사용할 수 있다.
function useInput(initialValue) {
const [value, setValue] = useState(initialValue);
const handleChange = (e) => {
setValue(e.target.value);
};
return [value, handleChange];
}
이렇게 정의된 useInput 훅을 다른 컴포넌트에서 간단하게 호출하여 사용할 수 있다:
function MyComponent() {
const [name, handleNameChange] = useInput("");
return (
<input value={name} onChange={handleNameChange} />
);
}
이처럼 커스텀 훅을 사용하면 코드의 재사용성과 가독성을 높일 수 있다.