1. 리액트에서 커스텀 훅을 만드는 방법
커스텀 훅을 만들 때에는 보통 use라는 키워드로 시작하는 파일을 만들고 그 안에 함수를 작성합니다.
커스텀 훅은 리액트 함수 컴포넌트에서 상태 관리, 사이드 이펙트 처리 등을 추상화하여 재사용 가능한 로직 단위로 만들어진 것입니다.
이를 통해 코드 중복을 줄이고 가독성을 높이며, 복잡한 컴포넌트를 간결하게 유지할 수 있습니다.
아래는 간단한 커스텀 훅의 예시입니다.
import { useState } from "react"; function useCustomHook() { const [state, setState] = useState(null); // 원하는 기능 구현 function doSomething() { // ... } return [state, doSomething]; } export default useCustomHook;
이 예시에서 useCustomHook은 커스텀 훅으로, useState를 사용하여 상태를 관리하고 있습니다.
doSomething 함수를 통해 원하는 기능을 구현하고, 필요한 값들을 반환하고 있습니다.
이렇게 만든 커스텀 훅은 다른 컴포넌트에서 재사용할 수 있습니다.
참고로, 커스텀 훅 내부에서는 useState, useEffect, useReducer, useCallback 등의 훅을 사용하여 원하는 기능을 구현하고,
컴포넌트에서 사용하고 싶은 값들을 반환하면 됩니다.
2. 리액트의 커스텀 훅(Custom Hook)은 기본적으로 리액트에서 제공하는 훅(Hook)을 조합하여
자신만의 훅을 만드는 것을 의미합니다.
이는 공통된 로직을 추출하고 재사용 가능한 로 직 단위로 만들어진 것으로, 코드 중복을 줄이고 가독성을 높이며, 복잡한 컴포넌트를 간결하게 유지할 수 있습니다.
커스텀 훅은 일반적으로 "use"로 시작하는 함수 이름으로 작성되며, 다른 컴포넌트에서 호출하여 사용할 수 있습니다2. 커스텀 훅 내부에서는 useState, useEffect, useReducer,
useCallback 등의 훅을 사용하여 원하는 기능을 구현하고, 컴포넌트에서 사용하고 싶은 값들을 반환하면 됩니다.
예를 들어, 아래는 useInputs라는 커스텀 훅의 예시입니다
import { useState, useCallback } from 'react'; function useInputs(initialForm) { const [form, setForm] = useState(initialForm); const onChange = useCallback(e => { const { name, value } = e.target; setForm(form => ({ ...form, [name]: value })); }, []); const reset = useCallback(() => setForm(initialForm), [initialForm]); return [form, onChange, reset]; } export default useInputs;
이 useInputs 훅은 입력 폼의 상태를 관리하는 로직을 재사용 가능하게 만들어줍니다.
이를 통해 여러 컴포넌트에서 동일한 로직을 쉽게 재사용할 수 있습니다
3. 예) 아래 useFetch는 커스텀 훅으로
소스 :
https://github.dev/braverokmc79/smple-react-nodejs
리액트 -장소 선택(place picker)
https://braverokmc79.github.io/react-place-picker/
useFetch는 커스텀 훅으로, 원격 데이터를 가져오는 로직을 재사용 가능하게 만들어줍니다.
이 훅은 fetchFn이라는 함수를 인자로 받아, 이 함수를 비동기적으로 실행하여 데이터를 가져옵니다.
useFetch 훅의 동작은 다음과 같습니다:
useState를 사용하여 isFetching, error, fetchedData라는 상태를 초기화합니다isFetching은
데이터를 가져오는 중인지 여부를 나타내며, error는 데이터를 가져오는 과정에서 발생한 오류를 저장하고, fetchedData는 가져온 데이터를 저장합니다.
useEffect를 사용하여 컴포넌트가 렌더링될 때 fetchFn 함수를 비동기적으로 실행합니다.
이 함수는 데이터를 가져오는 데 성공하면 fetchedData를 업데이트하고, 실패하면 error를 업데이트합니다.
isFetching, fetchedData, setFetchedData, error를 반환하여, 이 훅을 사용하는 컴포넌트에서 이 상태를 사용할 수 있게 합니다.
이렇게 useFetch를 사용하면, 원격 데이터를 가져오는 로직을 쉽게 재사용하고, 코드의 중복을 줄일 수 있습니다.
import { useState, useEffect } from "react"; export function useFetch(fetchFn, initialValue) { const [isFetching, setIsFetching] = useState(false); const [error, setError] = useState(null); const [fetchedData, setFetchedData]=useState(initialValue); useEffect(() => { async function fetchData() { setIsFetching(true); try { const data = await fetchFn(); // console.log("data",data); setFetchedData(data); } catch (error) { setError({ message: error.message || "데이터를 가져오는데 실패했습니다." }); } setIsFetching(false); } fetchData(); }, [fetchFn]); return{ isFetching, fetchedData, setFetchedData, error } }
useFetch 커스텀 훅 사용
AvailablePlaces
import Places from "./Places.jsx"; import Error from "./Error.jsx"; import { sortPlacesByDistance } from "../loc.js"; import { fetchAvailablePlaces } from "../http.js"; import { useFetch } from "../hooks/useFetch.js"; async function fetchSortedPlaces(){ const places=await fetchAvailablePlaces(); return new Promise((resolve) =>{ navigator.geolocation.getCurrentPosition((position)=>{ const sortedPlaces=sortPlacesByDistance(places, position.coords.latitude, position.coords.longitude); resolve(sortedPlaces); }); }); } export default function AvailablePlaces({ onSelectPlace }) { const {isFetching, error, fetchedData:availablePlaces}= useFetch(fetchSortedPlaces, []); if(error){ return <Error title="에러 발생됨!" message={error.message} /> } return ( <Places title="여행지 선택" places={availablePlaces} isLoading={isFetching} loadingText="데이터를 가져오는 중입니다...." fallbackText="여행지를 선택할수 없습니다." onSelectPlace={onSelectPlace} /> ); }
댓글 ( 0)
댓글 남기기