[React] Custom-hook 공식문서 번역

adam2·2019년 12월 25일
4
post-thumbnail

React 공식문서를 번역한 내용입니다.
번역에 오역이 있을 수 있으며 모든 내용을 번역한 것은 아닙니다.


커스텀 Hook 만들기

커스텀 hook을 만들면 컴포넌트 로직을 재사용 가능한 함수로 뽑아낼 수 있다.

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);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

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

이 코드는 팔로워의 online상태 여부를 알려준다. 여기에 온라인 상태인 팔로워는 초록 색으로 표시하고 싶을 때, 이 코드를 복붙해서 또다른 컴포넌트를 만드는 것은 너무 구리지 않은가?

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

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

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

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

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

위처럼 만드는 대신에 우리는 FriendsStatus와 FriendsListItem 사이에 중복된 로직을 공유하고싶어진다.

전통적인 리액트에서는 컴포넌트 사이에서 state관련된 로직을 공유하는 방법이 두가지가 있다. reder prophigher-order components 이다.
우리는 이제 hooks가 어떻게 이 문제를 해결하는지 알아볼 것이다.

커스텀 Hook 추출하기

우리는 보통 두개의 자바스크립트 함수가 같은 로직을 공유하게 하기 위해서 해당 로직을 함수로 뽑아서 재사용 가능하도록 만든다.

hookscomponent는 둘다 함수이기 때문에 우리는 이 방식을 잘활용하면 중복되는 state로직을 공유할 수 있지 않을까?

커스텀 hook은 다른 hook을 호출하는 자바스크립트 함수이다.
예를들어 useFriendStatus는 우리의 첫번째 커스텀 훅이다.

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

// 1. "use" 로 시작하고
function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

// 2. 다른 hook을 호출한다
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

위 함수를 보면 아까 중복된 로직과 똑같다는 것을 알 수 있다. 컴포넌트 안에서 그랬듯이 다른 hook을 호출할 때는 무조건 최상위 레벨에서 호출해야 한다. (hook 사용 규칙)

커스텀 훅 사용하기

이제 어떻게 우리가 만든 커스텀 훅을 사용하는지 알아보자.

앞서, 우리의 목표는 FriendStatusFriendListItem 컴포넌트 사이의 중복된 로직을 제거하는 것이었다. 우리는 중복 로직을 useFriendStatus 메소드로 추출하였고 이제 이 함수를 사용하기만 하면 된다.

function FriendStatus(props) {
// custom hook
  const isOnline = useFriendStatus(props.friend.id);

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

function FriendListItem(props) {
//custom hook
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

이 두개의 컴포넌트가 같은 hook을 사용했으니 같은 state를 공유하는걸까? 라고 생각하는 사람이 있을 것이다.

정답은 X!

커스텀 훅은 state와 관련된 로직을 재사용하기위한 하나의 매커니즘일 뿐이고 커스텀 훅을 사용한 컴포넌트의 모든 state와 effect는 완벽하게 분리되어있다.

그럼 어떻게 커스텀 훅은 독립된 state를 가지는 것일까?

우리는 컴포넌트(FriendListItem)안에서 커스텀 훅을 직접 호출했다. 리액트의 관점에서 이것은 맨처음 컴포넌트 안에서 직접 useState와 useEffect를 호출한 것과 똑같다. 그리고 우리는 한 컴포넌트 안에서 useState를 여러번 호출해도 각 state마다 독립적인것을 이미 알고 있다.

TIP

hook끼리 정보를 전달하기

hook은 함수이기때문에 우리는 hook끼리 정보를 주고받을 수 있다.

예를 들어보자면, 방금 만든 채팅예제를 다른 컴포넌트에서 사용한다 가정해보자. 컴포넌트의 이름은 chat message recipient picker이고 최근에 선택된 친구가 온라인 상태인지를 알려주는 역할을 한다.

const friendList = [
  { id: 1, name: 'Phoebe' },
  { id: 2, name: 'Rachel' },
  { id: 3, name: 'Ross' },
];

function ChatRecipientPicker() {
  const [recipientID, setRecipientID] = useState(1);
  const isRecipientOnline = useFriendStatus(recipientID);

  return (
    <>
      <Circle color={isRecipientOnline ? 'green' : 'red'} />
      <select
        value={recipientID}
        onChange={e => setRecipientID(Number(e.target.value))}
      >
        {friendList.map(friend => (
          <option key={friend.id} value={friend.id}>
            {friend.name}
          </option>
        ))}
      </select>
    </>
  );
}

최근에 선택된 팔로워 id를 recipientID 에 저장하고 select를 통해서 recipientID 값이 업데이트 된다.

useState 훅이 우리에게 가장 최신의 recipientID 값을 계속해서 주기 때문에 우리는 우리의 커스텀 훅에 파라미터로 지정해줄 수 있다.
useFriendStatus는 가장 최신의 recipientID 값을 파라미터로 받아 수행하므로 가장 최근에 선택된 친구의 온/오프라인 상태를 알려줄 수 있다.
만약 select를 통해 다른 친구를 선택한다면 setRecipientID를 통해 recipientID 가 새롭게 업데이트 될 것이고 새롭게 업데이트된 recipientID 로 커스텀훅은 온/오프라인여부를 또 찾아내 반환할 것이다.

0개의 댓글