React Hook

Franklee·2024년 5월 9일
0

React

목록 보기
5/7

보다 정확한 정보를 위해 지속적으로 업데이트하며 수정합니다.

React Hook

⭐ React Hook이란, 함수컴포넌트에서 React State와 생명주기 기능을 연동 할 수 있게 해주는 함수입니다.

함수컴포넌트

함수형컴포넌트와 함께 출시된것이 React Hook이다. 사실 Hook이 출시되면서 Hook을 사용한 애플리케이션 리팩토리과정을 소개하였고 이것이 바로 함수형컴포넌트의 작성방법이다. 이전에는 class,extends를 사용한 class형태의 컴포넌트가 있었지만, 당연하게도 여러단점에 의해 함수형 컴포넌트가 생겨났다고 볼 수 있다. 다만, 완전한 새로운 기술이 아닌 class형태의 사용에 있어 쉽고 간편하게 될 수 있는 부분을 새로운 형태로 바꾼것으로서 기술의 교체가 아닌 또 다른 방식이 나온것일 뿐이지, 앞으로도 class컴포넌트의 코드작성이 가능하다.

🔍 Hook이 도입되게된 이유 - React Document

  • 컴포넌트 사이에서 상태 로직을 재사용하기 어렵습니다. 🔗Link
  • 복잡한 컴포넌트들은 이해하기 어렵습니다. 🔗Link
  • Class은 사람과 기계를 혼동시킵니다. 🔗Link

🔔 Hook의 규칙

Hook을 사용함에 있어 2가지의 절대적인 규칙이 존재하고 이를 강제하기위해 linter 플러그인(eslint 기술)이 적용되어있다.

  • 최상위(at the Top Level)에서만 Hook을 호출해야 합니다
  • 오직 React 함수 내에서 Hook을 호출해야 합니다

이유를 알아보자.

단일 함수컴포넌트 내부에 다수의 Hook을 사용할 수 있는데, 이때 사용되는 다수의 Hook에 대한 다수의 state를 오류없이 어떻게 해당 Hook에 매칭을 시킬수 있을까? 이유는 간단하다. 바로 실행되는 순서에 따라 정해지기 때문이다.
공식문서에 따르면 "React가 Hook이 호출되는 순서에 의존한다는 것입니다." 라고 설명되어있다.

export default function Play(){
  const [game,setGame]=useState('A'); //실행순서 1
  const [football,setFootball]=useState('B'); //실행순서 2
  const [tennis,setTennis]=useState('C'); //실행순서 2
  
  return (...)
}

위에 사용된 useState라는 Hook은 컴포넌트가 랜더링될때 game-football-tennis의 순서대로 호출하고 이를 기억한다.
만약 해당 컴포넌트가 state의 변화로 리랜더링이 되었을때 어떠한 이유로 인해 호출순서에 변경이 일어난다면, 이전에 기억하고 있던 정보와 순서가 달라져 state가 올바른 Hook에 매칭이 되지 않을 경우, 호출 순서가 밀리게 되고, 버그를 발생기키게 된다.

즉, 호출순서가 변경되지 못하도록 하는 규칙이 필요하게되고, 위에서 언급한 2가지의 절대적인 규칙이 바로 이를 방지하기위한 룰이다.

export default function Play(){
  const [game,setGame]=useState('A'); //실행순서 1
  if(game === 'A'){
    useEffect(playGame);
  }
  const [football,setFootball]=useState('B'); //실행순서 2
  const [tennis,setTennis]=useState('C'); //실행순서 2
  
  return (...)
}

위 상황을 보면, 첫번째 랜더링시에는 if(game === 'A')의 값이 참이기 때문에 useEffect Hook이 정상실행 될 것이고, React는 game-playGame-football-tennis의 순서대로 기억할 것이다. 이때, game state가 변경되어 컴포넌트가 리랜더링을 진행했을때, game은 'A'가 아니게된 시점에서 useEffect Hook은 실행이 되지 않을 것이고, 호출 순서에 변경이 발생되어 결과적으로 버그가 발생될 것이다.

여기서 규칙을 적용시킨다고 가정하였을때 최상위(at the Top Level)에서만 Hook을 호출해야 합니다로 인해 if함수 내부에서 Hook을 호출할 수는 없다. 그런데 "컴포넌트 function Play()도 결과적으로 함수형태이기 때문에 최상위에서 호출해야한다는 것과 모순되지 않나?" 라고 할 수 있겠지만 오직 React 함수 내에서 Hook을 호출해야 합니다 의 규칙이 이를 보완(뒷받침)해주고 있다. 함수컴포넌트는 일반적인 javaScript 함수가 아닌 React 함수이기 때문에 컴포넌트내부에서 Hook을 호출하는 것이 가능하다. 더불어 Custom Hook 내부에서도 다른 Hook을 호출할 수 있는데 이 또한 위와 같은 이유로 가능한 것이다.

개발자가 2가지 규칙을 지키기 위해 이를 유의해가면서 코드를 작성할 필요는 없다. React 설치와 함께 linter 플러그인이 자동적용되어 규칙을 위반할 경우 컴파일에러( Compile error - 코드 작성단계에서의 오류발생 )가 발생할 것이다.


📌 Custom Hook

useState, useEffect, useContext 등 React에서 기본적으로 제공하는 Hook이 있다. 그런데 이러한 Hook을 직접 만들자고 하면 "이것을 어떻게 만들지..."라는 생각과 함께 머릿속이 복잡해질 터인데, 사실 매우 간단하다. Hook은 함수이다. 우리가 코딩을 하면서 여러가지 작업을 위해 코드를 작성하고 반복적으로 사용되는 작업을 중복해서 작성할 필요가 없도록 함수를 만든다. Custom Hook도 같은 이유와 원리로 만든다. 컴포넌트 랜더링시 어떠한 작업을 해야하고 이러한 동일한 작업이 다수의 컴포넌트에서 필요로 한다면, Hook을 만들어서 사용하는 것일 뿐이다.

정말 간단히 설명하자면, "상태 관련 로직을 컴포넌트끼리 공유하는 방법"이다.

🔍 Custom Hook (사용자정의 Hook) 제작 규칙

  • 함수명 제일 앞에 'use'를 작성해야한다. 이는 위에서 언급한 "Hook의 2가지 절대적인 규칙"을 지키기 위함이다.
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);
    };
  });//상태관리 로직

useState, useEffect를 사용하여 state를 다루게 되는데, useEffect의 내부 로직으로 인해 랜더링시에 해당 친구의 접속여부를 통해 상태표시를 변경하는 것이다. 이 로직을 어떠한 컴포넌트에서 실행시킨다고 가정하였을때 단순히 복사/붙여넣기를 통해 해결할 수 있지만, 코드 단축과 재사용성을 위해 Hook으로 만들어 사용해보도록 하겠다.

function useIsFriendOnline(id){
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(id, handleStatusChange);
    };
  });
  
  return isOnline;
}//Custom Hook

Hook의 완성이다. 함수명 앞에 use를 붙이고 알아보고자 하는 친구의 id를 매개변수로 받고, useState의 상태값이 useEffect의 내부로직에 의해 변경되고 return으로 값을 반환한다.

function FriendsList(){
  const isOnline = useIsFriendOnline('something');
  
  return(
    <li>
    	<p>{isOnline ? 'Online' : 'Offline'}</p>
    </li>
    )
}//Custom Hook을 컴포넌트에서 사용하기

Hook useIsFriendOnline의 리턴값이 isOnline에 할당되고 평소와 같이 사용하면 된다. 누군가는 "그냥 함수잖아? 뭐가 다른데?"라고 할 수 있는데, 컴포넌트 내부에 useStateuseEffect와 같은 Hook이 없다고 진짜 없는것이 아니다. 이미 언급했지만 로직공유, 코드단축, 재사용성을 위해 함수화 한것이지 실제로는 함수내부의 로직이 똑같이 컴포넌트 내부에 존재하는 것이고, 위에서 언급한 Hook의 2가지 절대적 규칙을 위반하지 않는 구현방식을 사용한 것이다. Custom Hook도 React 함수이다.

결과적으로 사용자정의 Hook또한 상태를 관리하기에 내부에 또 다른 Hook을 보유하고 있으며, Hook간의 정보 전달(props : 매개변수를 사용한)도 가능하다.


✨ Hook API

당연하게도 React에서는 이미 여러 Hook을 제공하고있으며, 이러한 Hook을 통해 새로운 Custom Hook을 제작할 수도 있다.
Custom Hook 또한 누군가가 이미 제작한 수많은 종류들을 여러 사이트를 통해 쉽게 찾아볼 수 있다.

[Hook API](React Hook API)

profile
복잡한 문제를 쉬운 코드로 해결해 나가는 개발자

0개의 댓글