tech

React Hook (1) - useState, useEffect

React Hook 중 useState와 useEffect만 자주 사용하고 나머지 Hook들은 잘 몰랐습니다. 이전 글에서 React 상태 관리를 공부하면서 다양한 Hook들이 활용성이 높다는 것을 알았으며, 공식문서를 읽으면서 참고하여 정리 중입니다.

 

Hook

Hook은 React버전 16.8부터 추가된 요소입니다. Hook을 이용하여 기존 Class 바탕으로 코드를 작성할 필요없이 상태 값과 여러 React의 기능을 사용할 수 있습니다. Hook이 만들어진 목적은 다음과 같습니다.

  • 컴포넌트 사이에서 상태 로직을 재사용하기 어렵다.
  • 복잡한 컴포넌트들은 이해하기 어렵다.
  • Class는 사람과 기계를 혼동시킵니다. -> Hook은 Class없이 React 기능들을 사용하는 방법을 제시합니다.

Hook은 함수 컴포넌트에서 React state와 생명주기 기능을 연동할 수 있게 해주는 함수입니다. class 안에서는 동작하지 않으며, class 없이 React를 사용할 수 있게 해줍니다. 내장 Hook을 살펴보겠습니다.

State Hook

import React, { useState } from 'react';

function Example() {
  // "count"라는 새 상태 변수를 선언합니다
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

위의 예시는 버튼을 클릭하면 값이 증가하는 간단한 타운터 예시입니다. useState가 바로 Hook이며, 사용하려면 Hook을 호출해 함수 컴포넌트 안에 state를 추가하여 사용할 수 있습니다. 이 state는 컴포넌트가 다시 렌더링 되어도 그대로 유지될 것입니다. useState는 현재의 state값과 이 값을 업데이트 하는 함수를 쌍으로 제공합니다. 이 함수를 이벤트 핸들러나 다른 곳에서 호출할 수 있으며, class의 this.setState와 비슷하지만, 이전 state와 새로운 state가 합치지 않는다는 차이점이 있습니다.

 

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

function ExampleWithManyStates() {
  // 상태 변수를 여러 개 선언했습니다!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

배열 구조 분해 문법은 useState로 호출된 state 변수들을 다른 변수명으로 할당할 수 있게 해줍니다. 이 변수명은 useState API와 관련이 없습니다. 대신 React는 매번 렌더링 할때 useState가 사용된 순서대로 실행할 것입니다. 

 

Effect Hook

React에서 'side effects'는 컴포넌트 안에서 데이터를 가져오거나 구독하고, DOM을 직접 조작하는 작업을 말합니다. 이것은 다른 컴포넌트에 영향을 줄 수도 있고, 렌더링 과정에서는 구현할 수 없는 작업이기 때문입니다.

 

Effect Hook, 즉 useEffect는 함수 컴포넌트 내에서 이런 side effects를 수행할 수 있게 해줍니다. class에서 componentDidMount  componentDidUpdate, componentWillUnmount와 같은 목적으로 제공되지만, 이것은 하나의 API로 통합된 것입니다. 

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // componentDidMount, componentDidUpdate와 비슷합니다
  useEffect(() => {
    // 브라우저 API를 이용해 문서의 타이틀을 업데이트합니다
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useEffect를 사용하면, React는 DOM을 바꾼 뒤에 'effect' 함수를 실행할 것입니다. Effects는 컴호넌트 안에 선언되어 있지 떄문에 props와 state에 접근할 수도 있습니다. 기본적으로 React는 매 렌더링 후에 effects를 실행합니다. 첫 번째 렌더링도 포함합니다.

 

Effect를 해제하고 싶다면 해제하는 함수를 반환할 수 있습니다. 이는 선택적이며, 이런 것이 있다는 건 처음 알았습니다 ..!

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

사용 방법은 위와 같으며, unmount될 때 React는 ChatAPI에서 구독을 해지할 것입니다. 또한 재렌더링이 일어나 effect를 재실행하기 전에도 마찬가지로 구독을 해지합니다. 

useState와 마찬가지로 컴포넌트 내에서 여러 개의 effect를 사용할 수 있습니다. 

 

Hook 사용 규칙

  • 최상위에서만 Hook을 호출해야합니다. 반복문, 조건문, 중첩된 함수 내에서 Hook을 실행하면 안됩니다.
  • React 함수 컴포넌트 내에서만 Hook을 호출해야 합니다. 일반 JavaScript 함수에는 Hook을 호출해서는 안됩니다. 

 

나만의 Hook을 만들어 다른 컴포넌트에서 재사용할 수도 있고, 앞서 언급했다싶이 보편적이지 않지만 유용한 Hook이 있습니다.