
React – 상태 관리와 Hooks – 커스텀 Hooks – 1 – 공통 로직 분리 및 재사용 예시
안녕하세요! 😊
이번에는 커스텀 훅을 어떻게 실제로 활용해서 공통 로직을 분리하고 재사용할 수 있는지 다양한 실전 예시 중심으로 알려드릴게요!
React 프로젝트가 커지면 똑같은 useEffect
, useState
로직이 이곳저곳에 반복되면서 코드가 지저분해지고 관리도 힘들어지잖아요?
그럴 때 커스텀 훅은 정말 구세주처럼 등장한답니다! 💡
오늘은 대표적인 예시들을 통해 “아~ 이렇게 쓰는구나!” 감을 확실히 잡아보세요!
1. 입력값 상태 관리 로직 분리 (useInput)
💬 어떤 문제?
React에서 input 요소를 사용할 때마다 항상 이런 코드를 반복하게 돼요:
const [value, setValue] = useState('');
const handleChange = (e) => setValue(e.target.value);
👉 이렇게 똑같은 로직을 여러 input마다 반복하는 건 비효율적이죠!
✅ 커스텀 훅으로 분리
import { useState } from 'react';
function useInput(initialValue = '') {
const [value, setValue] = useState(initialValue);
const onChange = (e) => {
setValue(e.target.value);
};
const reset = () => setValue(initialValue);
return { value, onChange, reset };
}
🎯 사용 예시
function LoginForm() {
const username = useInput('');
const password = useInput('');
return (
<div>
<input type="text" placeholder="아이디" {...username} />
<input type="password" placeholder="비밀번호" {...password} />
<button onClick={() => {
console.log(username.value, password.value);
username.reset();
password.reset();
}}>로그인</button>
</div>
);
}
🧠 useInput
하나로 깔끔하게 정리됐죠?
비유하자면 input을 다루는 매크로 키보드를 만든 거예요!
2. API 요청 로직 분리 (useFetch)
💬 어떤 문제?
컴포넌트 안에서 fetch 요청을 만들다 보면 중복이 많고, 로딩/에러 관리도 불편하죠.
✅ 커스텀 훅으로 분리
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(url)
.then(res => {
if (!res.ok) throw new Error('서버 응답 오류');
return res.json();
})
.then(json => {
setData(json);
setError(null);
})
.catch(err => setError(err))
.finally(() => setLoading(false));
}, [url]);
return { data, loading, error };
}
🎯 사용 예시
function UserList() {
const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users');
if (loading) return <p>불러오는 중...</p>;
if (error) return <p>에러 발생: {error.message}</p>;
return (
<ul>
{data.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
💡 useFetch
를 만들면 다른 컴포넌트에서도 동일한 방식으로 간편하게 데이터 불러오기 가능!
3. 디바운싱 처리 (useDebounce)
💬 어떤 문제?
검색창처럼 입력이 바뀔 때마다 API를 부르면 성능이 안 좋아요.
디바운싱은 입력 후 일정 시간 동안 입력이 없을 때만 동작하는 방식입니다.
✅ 커스텀 훅으로 분리
import { useState, useEffect } from 'react';
function useDebounce(value, delay = 500) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timeout = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timeout);
}, [value, delay]);
return debouncedValue;
}
🎯 사용 예시
function SearchInput() {
const [input, setInput] = useState('');
const debounced = useDebounce(input, 1000);
useEffect(() => {
if (debounced) {
console.log('검색 요청!', debounced);
// API 호출 가능
}
}, [debounced]);
return <input value={input} onChange={e => setInput(e.target.value)} />;
}
🧠 타자를 치는 도중에는 요청을 하지 않고, 입력이 멈췄을 때만 작동!
4. 이전 값 추적 (usePrevious)
💬 어떤 문제?
리렌더링 전 값을 비교하거나 기록하고 싶은 경우가 있어요.
✅ 커스텀 훅으로 분리
import { useEffect, useRef } from 'react';
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
🎯 사용 예시
function Counter() {
const [count, setCount] = useState(0);
const prev = usePrevious(count);
return (
<div>
<p>현재 값: {count}</p>
<p>이전 값: {prev}</p>
<button onClick={() => setCount(c => c + 1)}>+1</button>
</div>
);
}
🌱 이전 값을 기억해서 변경 전후 비교가 가능해져요!
5. 외부 클릭 감지 (useOutsideClick)
💬 어떤 문제?
모달, 드롭다운 같은 컴포넌트는 바깥 클릭 시 닫혀야 하는 경우가 많아요.
✅ 커스텀 훅으로 분리
import { useEffect } from 'react';
function useOutsideClick(ref, callback) {
useEffect(() => {
const handleClick = (e) => {
if (ref.current && !ref.current.contains(e.target)) {
callback();
}
};
document.addEventListener('mousedown', handleClick);
return () => document.removeEventListener('mousedown', handleClick);
}, [ref, callback]);
}
🎯 사용 예시
function Modal({ onClose }) {
const modalRef = useRef(null);
useOutsideClick(modalRef, onClose);
return (
<div ref={modalRef} className="modal">모달 내용</div>
);
}
✨ 이걸 매번 useEffect로 작성하면 너무 복잡한데,
useOutsideClick
으로 뚝딱 해결!
커스텀 훅 사용할 때 주의사항
항목 | 설명 |
---|---|
이름은 use 로 시작 |
React 규칙이므로 꼭 지켜야 함 |
조건문 안에서 호출 금지 | 훅은 항상 같은 순서로 호출돼야 함 |
상태 업데이트 외에 사이드 이펙트도 가능 | useEffect 포함 가능 |
너무 많은 로직을 넣지 말고 목적별로 분리 | 한 훅이 너무 비대해지면 유지보수가 어려워요 |
마무리하며
이제 여러분은 커스텀 훅으로 어떤 로직이든 분리하고 재사용할 수 있어요!
특히 팀 프로젝트에서는 이런 커스텀 훅을 잘 만들어두면
모든 컴포넌트가 간결하고 통일된 방식으로 작성될 수 있어 정말 편리해요! 🎉
✨ 오늘의 요약
🔹 커스텀 훅은 공통된 훅 로직을 함수로 추출한 것
🔹 상태 관리, 이벤트 처리, API 요청, 디바운싱 등 다양하게 활용
🔹 코드 재사용성, 가독성, 유지보수성 모두 향상!
다음에는 더 복잡한 예제를 통해 커스텀 훅을 다른 훅과 조합해서 사용하는 방법도 다뤄볼게요!
우리 같이 계속 성장해봐요! 💪🚀