이번 포스팅에서는 Custom Hook에 대해서 정리하겠습니다.
리액트에서 함수형 컴포넌트를 이용해서 개발을 진행하면 useState, useEffect와 같은 내장된 hook을 사용해서 편리하게 원하는 로직을 작성할 수 있습니다.
Custom Hook은 개발자가 스스로 원하는 Hook을 만들어 사용하는 것으로 코드를 재활용하여 코드량을 줄일 수 있습니다. 예를들어 데이터 패칭과 같은 반복된 작업이나 input에 의한 상태 변경 등을 Custom Hook을 통해 쉽게 사용할 수 있습니다.
Custom Hook을 사용하기 위해서 몇 가지 규칙이 있는데, 다음과 같습니다.
아래의 코드들은 리액트 공식 문서에 있는 컴포넌트입니다. FriendStatus와 FriendListItem 컴포넌트는 useState와 useEffect를 사용한 동일한 로직으로 구현됩니다.
//FriendStatus : 친구가 online인지 offline인지 return하는 컴포넌트
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';
}
//FriendListItem : 친구가 online일 때 초록색으로 표시하는 컴포넌트
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>
);
}
이런 상황에서 Custom Hook을 만들어 사용할 수 있습니다. useFriendStatus라는 Hook을 만들어 두 컴포넌트에 적용 시킵니다.
// 동일한 로직을 Custom Hook으로 구현
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
FriendStatus, FriendListItem 두 컴포넌트에 동일한 Custom Hook을 사용하더라도 state값은 컴포넌트 내에서 독립적으로 정의됩니다.
// 두 컴포넌트에 useFriendStatus Hook 적용
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);
return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}