icon안동민 개발노트

커스텀 훅 만들기


 커스텀 훅은 React의 내장 훅을 기반으로 만든 재사용 가능한 함수입니다.

 이를 통해 컴포넌트 로직을 추상화하고 재사용할 수 있어, 코드의 가독성과 유지보수성을 크게 향상시킬 수 있습니다.

커스텀 훅의 개념과 이점

 커스텀 훅은 다음과 같은 이점을 제공합니다.

  1. 로직 재사용 : 여러 컴포넌트에서 사용되는 공통 로직을 추출하여 재사용할 수 있습니다.
  2. 관심사 분리 : 복잡한 로직을 별도의 함수로 분리하여 컴포넌트를 더 깔끔하게 유지할 수 있습니다.
  3. 테스트 용이성 : 분리된 로직은 독립적으로 테스트하기 쉽습니다.

커스텀 훅 생성 방법

 커스텀 훅은 'use'로 시작하는 이름의 함수로 만듭니다

 이 함수 내부에서 React의 내장 훅을 사용할 수 있습니다.

 기본 구조

function useCustomHook(initialValue) {
  // 여기서 useState, useEffect 등의 훅 사용
  // ...
 
  return // 필요한 값이나 함수 반환
}

실제 사용 사례

  1. 폼 관리 훅

 폼 상태 관리를 위한 커스텀 훅을 만들어 보겠습니다.

import { useState } from 'react';
 
function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);
 
  const handleChange = (event) => {
    const { name, value } = event.target;
    setValues(prevValues => ({ ...prevValues, [name]: value }));
  };
 
  const resetForm = () => setValues(initialValues);
 
  return { values, handleChange, resetForm };
}
 
// 사용 예:
function LoginForm() {
  const { values, handleChange, resetForm } = useForm({ username: '', password: '' });
 
  const handleSubmit = (event) => {
    event.preventDefault();
    console.log('Form submitted:', values);
    resetForm();
  };
 
  return (
    <form onSubmit={handleSubmit}>
      <input
        name="username"
        value={values.username}
        onChange={handleChange}
      />
      <input
        type="password"
        name="password"
        value={values.password}
        onChange={handleChange}
      />
      <button type="submit">Login</button>
    </form>
  );
}
  1. 데이터 페칭 훅

 API 호출을 위한 커스텀 훅을 만들어 보겠습니다.

import { useState, useEffect } from 'react';
 
function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
 
  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        const json = await response.json();
        setData(json);
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    }
 
    fetchData();
  }, [url]);
 
  return { data, loading, error };
}
 
// 사용 예:
function UserProfile({ userId }) {
  const { data: user, loading, error } = useFetch(`https://api.example.com/users/${userId}`);
 
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
 
  return <div>{user.name}</div>;
}
  1. 윈도우 크기 감지 훅

 윈도우 크기 변화를 감지하는 커스텀 훅을 만들어 보겠습니다.

import { useState, useEffect } from 'react';
 
function useWindowSize() {
  const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
 
  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    };
 
    window.addEventListener('resize', handleResize);
 
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);
 
  return size;
}
 
// 사용 예:
function ResponsiveComponent() {
  const { width, height } = useWindowSize();
 
  return (
    <div>
      The window size is: {width} x {height}
    </div>
  );
}

훅 Composition

 커스텀 훅은 다른 커스텀 훅이나 내장 훅을 조합하여 더 복잡한 로직을 구현할 수 있습니다.

 이를 훅 composition이라고 합니다.

 예를 들어, 이전에 만든 useFetchuseForm 훅을 조합하여 데이터를 가져오고 수정하는 훅을 만들 수 있습니다.

function useUser(userId) {
  const { data: user, loading, error } = useFetch(`https://api.example.com/users/${userId}`);
  const { values, handleChange, resetForm } = useForm(user || {});
 
  useEffect(() => {
    if (user) {
      resetForm(user);
    }
  }, [user]);
 
  return { user: values, loading, error, handleChange };
}
 
// 사용 예:
function EditUserForm({ userId }) {
  const { user, loading, error, handleChange } = useUser(userId);
 
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
 
  return (
    <form>
      <input
        name="name"
        value={user.name}
        onChange={handleChange}
      />
      {/* 다른 필드들... */}
    </form>
  );
}

커스텀 훅 작성 시 주의사항

  1.  명명 규칙 : 커스텀 훅의 이름은 반드시 'use'로 시작해야 합니다. 이는 React가 해당 함수를 훅으로 인식하고 훅 규칙을 적용하기 위함입니다.

  2.  훅 규칙 준수 : 커스텀 훅 내부에서도 기본 훅 규칙(최상위에서만 호출, 조건부로 호출하지 않기 등)을 준수해야 합니다.

  3.  부작용 처리 : useEffect 등을 사용할 때 적절한 정리(cleanup) 함수를 반환하여 메모리 누수를 방지해야 합니다.

  4.  의존성 배열 주의 : useEffect 등의 훅에서 의존성 배열을 정확히 지정하여 불필요한 재실행을 방지해야 합니다.

  5.  반환값 일관성 : 훅의 반환값 구조를 일관되게 유지하여 사용자가 예측 가능하게 사용할 수 있도록 합니다.

 커스텀 훅은 React 애플리케이션에서 로직을 재사용하고 관심사를 분리하는 강력한 도구입니다.

 잘 설계된 커스텀 훅은 코드의 중복을 줄이고, 테스트 용이성을 향상시키며, 전반적인 코드 품질을 개선합니다.

 복잡한 상태 로직, 사이드 이펙트 처리, 브라우저 API 사용 등 다양한 시나리오에서 커스텀 훅을 활용할 수 있습니다.

 이를 통해 컴포넌트는 더 간결해지고 비즈니스 로직에 집중할 수 있게 되며, 재사용 가능한 로직은 프로젝트 전체에서 쉽게 공유될 수 있습니다.

 커스텀 훅을 효과적으로 사용하려면 적절한 추상화 수준을 찾는 것이 중요합니다.

 너무 특정한 용도로 만들면 재사용성이 떨어지고, 너무 일반적으로 만들면 사용하기 복잡해질 수 있습니다.

 프로젝트의 요구사항과 팀의 코딩 스타일을 고려하여 적절한 균형을 찾는 것이 좋습니다.