[Hook] 커스텀 훅과 그 종류

devAnderson·2022년 5월 2일
5

react hooks

목록 보기
1/1

0. 🚍 좋은 사이트를 찾아버렸다

최근 구글링을 통해 hooks와 관련한 내용이 있어서 살펴보다가 hooks를 마치 디자인 패턴처럼 정리해둔 사이트를 공유하길래 들어가보고 정말 많은 "shocking"한 경험을 하였다.

어렴풋이 hook 에 대해서 알고 있고, 요 근래 트랜드가 훅으로 로직들을 추상화하여 정리해서 사용하는 경우가 많길래 (React query, useAWS, graphql 의 useQuery 등등) 몇번 훅을 따로 만들어서 사용해보긴 했었지만 그렇게까지 큰 의미를 부여하지 않았다가
체계적으로 정리한 사이트를 보니 상당히 응용되는 부분이 많을 것 같아서 앞으로 시리즈별로 정리를 해볼까 한다.

해당 코드들을 분석하면서 나 역시도 훅을 적극적으로 이용한 개발을 하여 로직을 분리하는 방식을 사용해보고자 한다.

1. 🚍 Hook 이란?

일단 도입하기 전에 우선 "Hook 이 뭔가요?" 하는 물음에 대해서 답할 수 있어야 한다는 순간의 생각이 들어 정리하는 겸 적어보자면

Hook은 함수입니다. 이 함수들은 리엑트 컴포넌트 내에서 사용되어 상태나 라이프사이클 로직을 추상화해 저장하고, 재사용 가능한 로직을 분리할 수 있도록 도와줍니다. 대표적으로 useState, useEffect등과 같은 내장 훅 메서드들이 존재하며, 필요에 따라서 커스텀 훅을 제작할 수 있습니다.

사실 함수 컴포넌트에는 상태가 없고, 라이프사이클 관리를 하자니 기존 클래스의 복잡한 로직들을 포함하여 this의 사용으로 인한 혼선까지 겹쳐지면서 훅이라는 개념을 이용해 관리하는 상태와 라이프사이클 로직은 몹시 합리적이고 깔끔한 코드를 작성할 수 있게 도와준다고 할 수 있다.

2. 🚍 Hook의 원칙

a. 훅을 조건부 블록에서 사용하지 않는다
b. 훅을 일반 javascript 함수 스코프 내에서 호출하지 않는다. (하고싶다면 커스텀 훅에서 사용한다)

사실 두 조건은 이미 ESlint를 통해서 확인이 되기 때문에 굳이 이유는 알 필요는 없지만, 내용 설명에 따르면 리액트 앱이 해당 훅들의 호출 순서를 확실하게 신뢰할 수 있어야 하기 때문이라고 한다.

function Form() {
  const [name, setName] = useState('Mary');

  useEffect(function persistForm() {
    localStorage.setItem('formData', name);
  });

  const [surname, setSurname] = useState('Poppins');

  useEffect(function updateTitle() {
    document.title = name + ' ' + surname;
  });

  // ...
}

위의 내용에서도 볼 수 있듯, 한 컴포넌트 내부에서 hook 은 여러개 사용이 가능하다. 이때 react가 특정 state값이 어떤 useState에서 호출된 것인지를 알기 위해서 호출 순서를 가지고 파악을 한다고 한다.

따라서, 조건부로 호출을 할 경우

if(condition === true){
  const [name, setName] = useState('Mary');
}

리엑트 입장에서는 코드들을 읽어가다가 훅의 호출에서 해당 훅의 호출이 안되었을 가능성이 존재하므로, 원래 기대하던 훅의 순서에서 어긋나 버그를 발생시킬 수 있다.

또한, 일반 함수의 몸체 내에서 훅의 호출을 정의했을 경우, 이 함수가 호출되지 않는다면 역시나 훅이 호출될지 안될지 리엑트는 확신할 수 없으므로 기대하던 훅의 순서에서 어긋나게 된다.

function badPractice (){
  const [name, setName] = useState('Mary'); // 해당 badPractice가 호출되지 않는다면 이 훅의 호출을 보장할 수가 없다.
}

3. 🚍 custom hook

커스텀 훅이란, 위의 useState와 useEffect들과 같이, 특정 상태관리나 라이프사이클 로직들을 추상화하여 묶어서 재사용이 가능하도록 제작이 가능한 함수를 뜻한다.

형태는 이른바 "객체 지향적 개발" 과 매우 유사한 형태를 가진다.

즉, 특정 상태와 관련된 로직을 useState으로 정의하고, 이 state을 변경시킬 함수들을 객체로 담아 리턴하여 캡슐화한다

간단한 사용용례를 useToggle을 통해 구현해보자면

const useToggle = (initialState = false) => {
    const [state, setState] = useState(initialState);
    const toggle = useCallback(() => setState(state => !state), []);
    
    return [state, toggle]
}

// usage
import { useCallback, useState } from 'react';

function App() {
    const [isTextChanged, setIsTextChanged] = useToggle();
    
    return (
        <button onClick={setIsTextChanged}>{isTextChanged ? 'Toggled' : 'Click to Toggle'}</button>
    );
}

위처럼 useToggle을 호출하면 현재 토글상태과, 이 토글상태를 변경할 수 있는 함수가 리턴이 된다.
훅을 호출하면 destructuring을 통해 리턴값을 특정 변수와 바인딩하여 사용할 수 있는 것이다.

커스텀 훅의 강점은 불필요하게 반복되는 로직을 하나의 함수로 묶어서 재활용이 가능하도록 만든다는 점에서 그 의의가 있으므로 활용할 수록 좋다고 할 수 있다.

4. useHooks

이처럼 커스텀 훅은 좋긴 하지만 사용방식을 익히는 데에 까다롭고 응용하려면 나름의 노하우들이 필요하다.
따라서 이것을 위해서는 좋은 훅을 보면서 연구하는 습관을 들일 필요가 있다. 이를 위한 레퍼런스를 남겨두고 앞으로 훅을 하나하나 연구해보며 블로깅을 해볼 생각이다.

useHooks hompage

profile
자라나라 프론트엔드 개발새싹!

0개의 댓글