2 minute read

React Hook(2)

Effect Hook

Effect Hook은 컴포넌트가 렌더링 이후에 어떤 일을 수행해야 하는지 설정하는 Hook이다.

  • DOM 업데이트 한 뒤 추가로 코드를 실행한다. (side effects 필요시 해당 코드 실행)
  • 기본적으로 React는 매 렌더링 이후 Effect Hook 실행
  • 함수 컴포넌트에서 React의 생명주기 메서드처럼 사용할 수 있다.
    • componentDidMount()
    • componentDidUpdate()
    • componentWillUnmount()
  • 한 컴포넌트 안에 useEffect()를 여러번 사용할 수 있다.

useEffect()의 기본 형태는 아래와 같다.

import React, {useEffect} from "react";

function MyComponent(props) {
  /* 렌더링시 콜백을 실행 */
  useEffect(
    콜백
  )
}

다음은 리액트 공식문서에 나와있는 예제 코드이다.

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

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

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

위 예제는 버튼 클릭 시 count값이 +1로 변경되고 그때마다 새로 렌더링 된다. 이때 useEffect()의 콜백이 실행된다.


또 다른 예시를 보자.

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

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // effect 이후에 어떻게 정리(clean-up)할 것인지 표시합니다.
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

위 예제는 구독을 설정하는 코드이다. 이처럼 effect를 위한 추가적인 정리(clean-up)가 필요할 때, effect 내부에서 정리를 위한 함수를 반환할 수 있다. 이 점이 구독(subscription)의 추가와 제거를 위한 로직을 가까이 묶어둘 수 있게 한다.

요약

effect에 정리(clean-up)가 필요한 경우에는 함수를 반환한다.

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

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

정리(clean-up)가 필요없는 경우에는 어떤 것도 반환하지 않는다.

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

이처럼 effect Hook은 두 가지 경우를 한 개의 API로 통합한다.

조건부 effect 실행

effect의 기본 동작은 모든 렌더링을 완료한 후 effect를 발생하는 것이다. 이와 같은 방법으로 의존성 중 하나가 변경되면 effect는 항상 재생성된다.

그러나 이것은 위의 구독 예제처럼 일부 경우에 과도한 작업일 수 있다. 이럴때 useEffect에 두 번째 인자를 전달하면 이 인자가 변경될 때에만 재생성 된다.

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source], // props.source가 변경될 때에만 구독이 재생성된다.
);

단 한 번만 실행되는 effect함수

만약 종속성 목록에 아무런 종속성도 없다면, 다시 말해 두 번째 인자에 빈 배열[]로 둘 경우에는 컴포넌트가 처음 생성될때만 effect함수가 실행된다. 이를 통해 effect는 React에게 props나 state에서 가져온 어떤값에도 의존하지 않으므로, 다시 실행할 필요가 전혀 없다는 것을 의미한다. 대표적으로 처음 한 번만 외부 API를 통해 리소스를 받아오고 더이상 API호출이 필요하지 않을 때에 사용된다.