[React Docs] Custom Hooks

lyshine·2023년 6월 18일
0

React

목록 보기
2/6
post-thumbnail

Custom Hooks

  • 개요
    리액트에는 useState, useContext, useEffect 같은 빌트인 훅들이 있다.
    ⇒ 커스텀 훅은 리액트에서 더 구체적인 목적을 위한 훅을 만들기 위함으로 필요에 따라서 자신만의 훅을 만들 수 있다.

Learn About..

  • 커스텀 훅이란 무엇이며, 직접 작성하는 방법
  • 컴포넌트 간에 로직을 재사용하는 방법
  • 커스텀 훅의 이름을 만들고 구조화하는 방법
  • 커스텀 훅을 추출해야 하는 시기와 이유

커스텀 훅: 컴포넌트간의 로직 공유& 컴포넌트에서 커스텀 훅 추출하기

  • 다른 두 컴포넌트가 공통된 기능(로직)을 요구하는 경우, 두 컴포넌트 간의 로직이 중복될 수 있다. ⇒ 로직 재사용하고 싶음!
  • 커스텀 훅을 직접 만들어 컴포넌트에서 중복된 코드를 없앨 수 있다.
function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() => {
    function handleOnline() {
      setIsOnline(true);
    }
    function handleOffline() {
      setIsOnline(false);
    }
    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);
    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);
  return isOnline; //리턴값 : 컴포넌트들이 이 값을 읽을 수 있다.
}
import { useOnlineStatus } from './useOnlineStatus.js';

//컴포넌트1
function StatusBar() {
  const isOnline = useOnlineStatus();
  return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>;
}

//컴포넌트2
function SaveButton() {
  const isOnline = useOnlineStatus();

  function handleSaveClick() {
    console.log('✅ Progress saved');
  }

  return (
    <button disabled={!isOnline} onClick={handleSaveClick}>
      {isOnline ? 'Save progress' : 'Reconnecting...'}
    </button>
  );
}

export default function App() {
  return (
    <>
      <SaveButton />
      <StatusBar />
    </>
  );
}

⇒ 커스텀 훅을 사용함으로써, 컴포넌트 내부의 코드가 어떻게 할것인가가 아닌, “무엇을 할것인가”를 설명한다.

⇒ 지저분한 세부 사항을 숨길 수 있다. (컴포넌트의 내부 코드는 구현이 아니라 의도를 표현)

커스텀훅 사용 규칙

  1. 훅의 이름은 use~로 시작해야 한다.
  2. 임의의 값을 반환할 수 있다.

커스텀 훅은 state 자체가 아닌 상태적인 로직(stateful logic)을 공유

  • 커스텀 훅은 state 자체가 아닌 상태적인 로직(stateful logic)을 공유한다.
    • 상태 로직은 공유할 수 있지만 state 자체는 공유할 수 없다.
    • 각 컴포넌트에서의 커스텀훅 호출은 완전히 독립적이다.

특징

  • 커스텀 훅도 순수해야 한다. (컴포넌트를 다시 렌더링할때마다 커스텀 훅 내부의 코드가 다시 실행되기 때문)
  • 컴포넌트 안에서 어떻게 동작하는지 알 필요없이 사용할 수 있으며 다른 컴포넌트에 추가하고 다른 옵션을 전달해도 똑같은 방식으로 동작하게 된다.
  • 커스텀 훅의 이름은 무엇을 하고, 무엇을 취하고, 무엇을 반환하는지 짐작할 수 있을 정도로 명확하게 지어야 한다.

커스텀훅은 언제 사용해야 할까?

  • 커스텀 훅은 중복되는 로직을 재사용하고 싶을 때 사용할 수 있지만 그렇다고 중복되는 모든 코드에 대해 커스텀 훅을 추출하면 불필요하게 사용될 수 있어 적절한 상황에 사용해야 한다.

  • Effect를 작성할때마다 커스텀 훅으로 감싸는 것이 좋을지 생각해본다. Effect를 커스텀 훅으로 감싸면 의도와 데이터 흐름 방식을 정확하게 전달 가능

    • 커스텀 훅을 추출하면 데이터 흐름을 명시적으로 만들 수 있다.

예시> 도시 목록을 표시하는 드롭다운과 선택한 도시의 지역 목록을 표시하는 드롭다운 두 개를 표시

  • 커스텀훅 사용전
function ShippingForm({ country }) {
  const [cities, setCities] = useState(null);
  // This Effect fetches cities for a country
  // 이 Effect는 국가의 도시들을 페치합니다
  useEffect(() => {
    let ignore = false;
    fetch(`/api/cities?country=${country}`)
      .then(response => response.json())
      .then(json => {
        if (!ignore) {
          setCities(json);
        }
      });
    return () => {
      ignore = true;
    };
  }, [country]);

  const [city, setCity] = useState(null);
  const [areas, setAreas] = useState(null);
  // This Effect fetches areas for the selected city
  // 이 Effect는 선택된 도시의 장소들을 페치합니다
  useEffect(() => {
    if (city) {
      let ignore = false;
      fetch(`/api/areas?city=${city}`)
        .then(response => response.json())
        .then(json => {
          if (!ignore) {
            setAreas(json);
          }
        });
      return () => {
        ignore = true;
      };
    }
  }, [city]);

  // ...
  • 커스텀훅 사용후 : 공통 로직을 자체 useDate 훅으로 추출

url을 입력하면 data를 가져올 수 있다.

//커스텀 훅 useData
function useData(url) {
  const [data, setData] = useState(null);
  useEffect(() => {
    if (url) {
      let ignore = false;
      fetch(url)
        .then(response => response.json())
        .then(json => {
          if (!ignore) {
            setData(json);
          }
        });
      return () => {
        ignore = true;
      };
    }
  }, [url]);
  return data;
}
function ShippingForm({ country }) {
  const cities = useData(`/api/cities?country=${country}`);
  const [city, setCity] = useState(null);
  const areas = useData(city ? `/api/areas?city=${city}` : null);
  // ...
  • 커스텀 훅을 추출하여 데이터 흐름을 명시적으로 만들게 된다.
  • useData 안에 Effect를 “숨기면” ShippingForm 컴포넌트에서 작업하는 사람이 불필요한 의존성을 추가하는 것을 방지할 수 있다.

커스텀훅의 마이그레이션

커스텀 훅은 더 나은 패턴으로 마이그레이션하는데에 도움을 준다.

  • 시간이 지남에 따라, React 팀의 목표는 더 구체적인 문제에 대한 더 구체적인 솔루션을 제공함으로써 “앱에서 Effect의 수를 최소한으로 줄이는 것”
  • Effect를 커스텀 훅으로 감싸면 이러한 솔루션이 제공될 때 코드를 더 쉽게 업그레이드 가능하다.
  • design system과 비슷하게 앱의 컴포넌트에서 공통된 관용구를 추출하여 커스텀 훅으로 만드는 것이 도움이 될 수 있다.
    • 컴포넌트의 코드가 의도에 집중, raw Effect를 자주 사용하는 것을 방지할 수 있다.
  • 종종 커스텀 훅으로 Effect를 감싸는 것이 좋은 또 다른 이유
  1. Effect와의 데이터 흐름을 매우 명확하게 만들 수 있습니다.
  2. 컴포넌트가 Effect의 정확한 구현보다는 의도에 집중할 수 있습니다.
  3. React가 새로운 기능을 추가할 때 어떤 컴포넌트도 변경하지 않고 해당 Effect를 제거할 수 있습니다.

출처(리액트 공식문서) : https://react.dev/learn/reusing-logic-with-custom-hooks

0개의 댓글