Custom hook 만들기

이보아·2024년 6월 12일

Custom hook 이란?

커스텀 훅을 사용하면 코드 재사용성을 높이고, 컴포넌트의 로직을 더 깔끔하게 분리할 수 있다.


custom hook 장점

  1. 코드 재사용성: 반복되는 로직을 커스텀 훅으로 분리하여 여러 컴포넌트에서 재사용할 수 있습니다. 이를 통해 코드 중복을 줄이고, 유지보수를 쉽게 할 수 있다.

  2. 컴포넌트의 가독성 향상: 데이터 페칭, 상태 관리 등 복잡한 로직을 커스텀 훅으로 분리하여 컴포넌트의 코드가 간결해집니다. 이렇게 하면 컴포넌트는 UI에만 집중할 수 있게 되어 가독성이 높아집니다.

  3. 테스트 용이성: 커스텀 훅을 사용하면 비즈니스 로직을 독립적으로 테스트할 수 있습니다. 훅을 별도로 테스트하여 컴포넌트의 의존성을 줄이고, 테스트 코드를 간단하게 유지할 수 있다.

  4. 상태와 로직 분리: 커스텀 훅을 사용하면 상태와 로직을 컴포넌트에서 분리하여 관심사의 분리가 명확해집니다. 이를 통해 코드를 더 모듈화하고, 각 부분의 역할을 명확히 할 수 있다.


들어가기에 앞서

useExpenses라는 커스텀 훅을 만들어 간단한 지출 목록을 만드려 한다.axios를 사용하여 서버에서 데이터를 가져오고 커스텀 훅을 사용하여 데이터를 컴포넌트에 전달 하는것까지 구현 해보려 한다.


1. AXios 설치

HTTP 요청을 위해 axios를 설치한다.

npm install axios

2. API 설정

서버와 통신하기 위해 axios 인스턴스를 설정한다. 이를 통해 API 호출을 더 쉽게 할 수 있다.

// src/axios/api.js
import axios from 'axios';

// 기본 URL을 설정합니다.
const api = axios.create({
    baseURL: 'http://localhost:5000',
});

export default api;


3. 커스텀 훅 생성 ⭐

! 이 훅은 데이터를 가져오고, 로딩 상태와 에러 상태를 관리한다. 이번 글에서 가장 중요한 부분이니, 코드를 세세하게 살펴보자! 🤓

// src/hooks/useExpenses.js
import { useState, useEffect } from 'react';
import api from '../axios/api';

const useExpenses = () => {
    const [expenses, setExpenses] = useState([]); // 지출 데이터를 저장할 상태
    const [loading, setLoading] = useState(true); // 로딩 상태
    const [error, setError] = useState(null); // 에러 상태

    useEffect(() => {
        const fetchExpenses = async () => {
            try {
                const response = await api.get('/expenses'); // API 요청
                setExpenses(response.data); // 데이터 저장
            } catch (err) {
                setError(err); // 에러 저장
            } finally {
                setLoading(false); // 로딩 완료
            }
        };

        fetchExpenses();
    }, []);

    return { expenses, loading, error }; // 상태 반환
};

export default useExpenses;

1. 상태 변수 초기화: useState를 사용하여 세 가지 상태 변수를 초기화한다.

  • expenses: 지출 데이터를 상태
  • loading: 데이터 로딩 상태
  • error: 에러 상태

    const [expenses, setExpenses] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

2. 데이터 가져오기: useEffect 훅을 사용하여 컴포넌트가 처음 마운트될 때 서버에서 지출 데이터를 가져온다.


   useEffect(() => {
        const fetchExpenses = async () => {
            try {
                const response = await api.get('/expenses'); // 서버에서 데이터 가져오기
                setExpenses(response.data); // 가져온 데이터를 상태에 저장
            } catch (err) {
                setError(err); // 에러가 발생하면 에러 상태에 저장
            } finally {
                setLoading(false); // 데이터 로딩이 끝나면 로딩 상태를 false로 설정
            }
        };

        fetchExpenses();
    }, []);
  • fetchExpenses라는 비동기 함수를 정의하여 axios를 통해 서버에서 데이터를 가져 온다.
  • 데이터를 성공적으로 가져오면 expenses 상태에 저장한다.
  • 에러가 발생하면 error 상태에 저장함
  • 데이터를 가져오는 작업이 완료되면 loading 상태를 false로 설정한다.
  • 상태 반환: expenses, loading, error 상태를 반환하여 이 훅을 사용하는 컴포넌트에서 해당 상태를 사용할 수 있도록 한다.

3. 상태 반환


    return { expenses, loading, error };
}
  • 마지막으로 expenses, loading, error 상태를 반환한다. 이 훅을 사용하는 컴포넌트에서 이 세 가지 상태를 사용할 수 있다.

4. 커스텀 훅 사용하기

이 훅을 사용해서 지출 데이터를 화면에 보여준다.

// src/components/ExpenseList.js
import React from 'react';
import useExpenses from '../hooks/useExpenses';

const ExpenseList = () => {
    const { expenses, loading, error } = useExpenses(); // 커스텀 훅 사용

    if (loading) return <p>로딩 중...</p>; // 로딩 중일 때
    if (error) return <p>에러가 발생했습니다.</p>; // 에러가 발생했을 때

    return (
        <ul>
            {expenses.map((expense) => (
                <li key={expense.id}>
                    {expense.item}: {expense.amount}</li>
            ))}
        </ul>
    );
};

export default ExpenseList;

5. 최종 컴포넌트 설정


// src/App.js
import React from 'react';
import ExpenseList from './components/ExpenseList';

const App = () => {
    return (
        <div>
            <h1>지출 목록</h1>
            <ExpenseList />
        </div>
    );
};

export default App;

6. JSON 서버 설정 (옵션)

위의 예제는 http://localhost:5000/expenses 엔드포인트를 사용했다. 이를 위해 간단한 JSON 서버를 설정할 수 있다.

JSON 서버 설치

npm install -g json-server

db.json 생성

db.json 파일을 프로젝트 루트에 생성한다. (src)

{
  "expenses": [
    { "id": 1, "item": "커피", "amount": 4000 },
    { "id": 2, "item": "샌드위치", "amount": 5500 }
  ]
}

JSON 서버 실행하기

json-server --watch db.json --port 5000

🤓 이때! package.json에 미리 설정해두면 해당 명령어로 간편하게 서버를 실행 시킬 수 있기때문에 미리 등록 해두는것이 좋다. 등록한 뒤에는 npm run json을 하면 위의 명령어와 동일하게 json 서버를 실행 시킬 수 있다.

// package.json
  "scripts": {
         ...
        "json": "json-server --watch src/db.json --port 5000"
    },

마무리

커스텀 훅을 잘 사용하면 코드의 재사용성을 높이고, 코드가 더 모듈화되어 좋은거 같다. 필요한 부분이 있다면 커스텀 훅을 많이 만들어보는 연습을 해야겠다!

profile
매일매일 틀깨기

0개의 댓글