codinghatso

React Hook이란? 본문

WEB/React

React Hook이란?

hatso 2023. 10. 23. 22:08

Hook이란?

React 16.8에 새로 추가된 기능. Hook은 class를 작성하지 않고도 state와 다른 react의 기능들을 사용할 수 있도록 해준다.

Hook은 특별한 함수이다.

예를 들어 "useState"(Hook함수) state를 함수 컴포넌트 안에서 사용할 수 있게 해 줍니다.

 

기존 에는 state를 추가하고 싶을 때 클래스 컴포넌트로 바꾸곤 했습니다.

하지만 이제 함수 컴포넌트 안에서 Hook을 이용하여 state를 사용할 수 있습니다.

 

Hook의 규칙

  1. 최상위(at the Top Level)에서만 Hook을 호출해야 합니다.
    • 반복문, 조건문 혹은 중첩된 함수 내에서 Hook을 호출하지 마세요.
    • 이 규칙을 따르면 컴포넌트가 렌더링 될 때마다 항상 동일한 순서로 Hook이 호출되는 것이 보장됩니다.
  2. 오직 React 함수 내에서 Hook을 호출해야 합니다.
    • Hook을 일반적인 JavaScript 함수에서 호출하지 마세요.
    • React 함수 컴포넌트에서 Hook을 호출하세요.
    • Custom Hook에서 Hook을 호출하세요.

Hook의 규칙을 강제하는 eslint-plugin-react-hooks라는 ESLint플러그인을 출시했고, 이 플러그인은 Create React App에 기본적으로 포함되어 있습니다.

npm install eslint-plugin-react-hooks --save-dev
// ESLint 설정 파일
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
    "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies
  }
}

설명

한 컴포넌트에서 State나 Effect Hook을 여러 개 사용할 수도 있습니다.

function Form() {
  // 1. name이라는 state 변수를 사용하세요.
  const [name, setName] = useState('Mary');

  // 2. Effect를 사용해 폼 데이터를 저장하세요.
  useEffect(function persistForm() {
    localStorage.setItem('formData', name);
  });

  // 3. surname이라는 state 변수를 사용하세요.
  const [surname, setSurname] = useState('Poppins');

  // 4. Effect를 사용해서 제목을 업데이트합니다.
  useEffect(function updateTitle() {
    document.title = name + ' ' + surname;
  });

  // ...
}

React가 Hook의 호출되는 순서에 의존한다는 것입니다.

모든 렌더링에서 Hook의 호출 순서는 같기 때문에 예시가 올바르게 동작할 수 있습니다.

// ------------
// 첫 번째 렌더링
// ------------
useState('Mary')           // 1. 'Mary'라는 name state 변수를 선언합니다.
useEffect(persistForm)     // 2. 폼 데이터를 저장하기 위한 effect를 추가합니다.
useState('Poppins')        // 3. 'Poppins'라는 surname state 변수를 선언합니다.
useEffect(updateTitle)     // 4. 제목을 업데이트하기 위한 effect를 추가합니다.

// -------------
// 두 번째 렌더링
// -------------
useState('Mary')           // 1. name state 변수를 읽습니다.(인자는 무시됩니다)
useEffect(persistForm)     // 2. 폼 데이터를 저장하기 위한 effect가 대체됩니다.
useState('Poppins')        // 3. surname state 변수를 읽습니다.(인자는 무시됩니다)
useEffect(updateTitle)     // 4. 제목을 업데이트하기 위한 effect가 대체됩니다.

// ...

Hook의 호출 순서가 렌더링 간에 동일하다면 React는 지역적인 state를 각 Hook에 연동시킬 수 있습니다.

하지만 Hook을 조건문 안에서 호출한다면 어떤 일이 일어날까요?

// 🔴 조건문에 Hook을 사용함으로써 첫 번째 규칙을 깼습니다
  if (name !== '') {
    useEffect(function persistForm() {
      localStorage.setItem('formData', name);
    });
  }

name !== '' 조건은 첫 번째 렌더링에서 true 기 때문에 Hook은 동작합니다.

하지만 사용자가 그다음 렌더링에서 폼을 초기화하면서 조건을 false로 만들 겁니다.

렌더링 간에 Hook을 건너뛰기 때문에 Hook 호출 순서가 달라집니다.

useState('Mary')           // 1. name state 변수를 읽습니다. (인자는 무시됩니다)
// useEffect(persistForm)  // 🔴 Hook을 건너뛰었습니다!
useState('Poppins')        // 🔴 2 (3이었던). surname state 변수를 읽는 데 실패했습니다.
useEffect(updateTitle)     // 🔴 3 (4였던). 제목을 업데이트하기 위한 effect가 대체되는 데 실패했습니다.

Hook을 건너뛰면서 다음에 호출되는 Hook의 순서가 하나씩 밀리면서 버그를 발생시키게 됩니다.

 

이것이 컴포넌트 최상위(the top of level)에서 Hook이 호출되어야만 하는 이유입니다.

조건부로 effect를 실행하기를 원한다면, 조건문을 Hook 내부에 넣을 수 있습니다.

useEffect(function persistForm() {
    // 👍 더 이상 첫 번째 규칙을 어기지 않습니다
    if (name !== '') {
      localStorage.setItem('formData', name);
    }
  });

제공된 lint 규칙을 활용한다면 이 문제에 대해 걱정할 필요는 없습니다.

 

정리

Hook은 함수 컴포넌트 안에서 state를 사용할 수 있게 해 줍니다.

하나의 컴포넌트에서 여러 개 사용가능합니다.

모든 렌더링에서 Hook의 호출 순서는 같습니다.

Hook을 사용할 때 2가지 규칙을 지켜야 하며, 규칙을 지키지 않았을 때 버그가 발생할 수 있습니다.

'WEB > React' 카테고리의 다른 글

useContext - React Hooks  (0) 2023.11.03
useRef - React Hooks  (0) 2023.11.01
useEffect - React Hooks  (0) 2023.11.01
useState - React Hooks  (2) 2023.10.23
학습 체크리스트  (0) 2023.10.20
Comments