Hooks
React Hooks
React Hooks는 함수 컴포넌트에서 상태 관리와 생명주기 기능을 사용할 수 있게 해주는 React 16.8에서 도입된 혁신적인 기능입니다. useState, useEffect, useContext 등을 통해 클래스 컴포넌트 없이도 완전한 React 애플리케이션을 구축할 수 있습니다.
React Hooks
React Hooks는 함수 컴포넌트에서 상태 관리와 생명주기 기능을 사용할 수 있게 해주는 React 16.8에서 도입된 혁신적인 기능입니다. useState, useEffect, useContext 등을 통해 클래스 컴포넌트 없이도 완전한 React 애플리케이션을 구축할 수 있습니다.
React Hooks는 2019년 React 16.8에서 정식 출시된 기능으로, 함수 컴포넌트에서 상태(state)와 생명주기(lifecycle) 기능을 사용할 수 있게 해줍니다. Hooks 이전에는 이러한 기능을 사용하려면 반드시 클래스 컴포넌트를 작성해야 했습니다. Hooks의 등장으로 함수 컴포넌트만으로도 완전한 기능을 갖춘 React 애플리케이션을 개발할 수 있게 되었습니다.
기본 Hooks에는 useState(상태 관리), useEffect(부수 효과 처리), useContext(컨텍스트 사용)가 있습니다. useState는 컴포넌트에 상태 변수를 추가하고, useEffect는 데이터 페칭, 구독, DOM 조작 등의 부수 효과를 처리합니다. useContext는 prop drilling 없이 컴포넌트 트리 전체에서 데이터를 공유할 수 있게 해줍니다.
추가 Hooks로는 useReducer(복잡한 상태 로직), useCallback(함수 메모이제이션), useMemo(값 메모이제이션), useRef(변경 가능한 ref 객체), useLayoutEffect(동기 DOM 업데이트), useImperativeHandle(ref 커스터마이징) 등이 있습니다. React 18에서는 useId, useTransition, useDeferredValue 등 새로운 Hooks가 추가되어 동시성 기능을 지원합니다.
커스텀 훅(Custom Hook)은 use로 시작하는 함수로, 여러 컴포넌트에서 재사용할 로직을 추출할 수 있습니다. useForm, useFetch, useLocalStorage 같은 커스텀 훅을 만들어 코드 중복을 줄이고 관심사를 분리할 수 있습니다. Hooks 규칙(최상위에서만 호출, React 함수 내에서만 호출)을 준수하면 예측 가능하고 일관된 동작을 보장받을 수 있습니다.
import { useState, useEffect, useCallback, useMemo } from 'react';
// 커스텀 훅: 데이터 페칭
function useFetch<T>(url: string) {
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const abortController = new AbortController();
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url, {
signal: abortController.signal
});
if (!response.ok) throw new Error('Network response was not ok');
const result = await response.json();
setData(result);
} catch (err) {
if (err.name !== 'AbortError') {
setError(err as Error);
}
} finally {
setLoading(false);
}
};
fetchData();
// 클린업: 컴포넌트 언마운트 시 요청 취소
return () => abortController.abort();
}, [url]);
return { data, loading, error };
}
// 커스텀 훅: 로컬 스토리지
function useLocalStorage<T>(key: string, initialValue: T) {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch {
return initialValue;
}
});
const setValue = useCallback((value: T | ((val: T) => T)) => {
setStoredValue(prev => {
const valueToStore = value instanceof Function ? value(prev) : value;
window.localStorage.setItem(key, JSON.stringify(valueToStore));
return valueToStore;
});
}, [key]);
return [storedValue, setValue] as const;
}
// 메인 컴포넌트
function UserDashboard() {
const [searchTerm, setSearchTerm] = useState('');
const [theme, setTheme] = useLocalStorage('theme', 'dark');
const { data: users, loading, error } = useFetch<User[]>('/api/users');
// 검색 결과 메모이제이션
const filteredUsers = useMemo(() => {
if (!users) return [];
return users.filter(user =>
user.name.toLowerCase().includes(searchTerm.toLowerCase())
);
}, [users, searchTerm]);
// 이벤트 핸들러 메모이제이션
const handleSearch = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(e.target.value);
}, []);
const toggleTheme = useCallback(() => {
setTheme(prev => prev === 'dark' ? 'light' : 'dark');
}, [setTheme]);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div data-theme={theme}>
<button onClick={toggleTheme}>Toggle Theme</button>
<input
type="text"
value={searchTerm}
onChange={handleSearch}
placeholder="Search users..."
/>
<ul>
{filteredUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
💬 상황: 기술 면접에서 Hooks 사용 경험에 대해 질문하는 상황