On this page
React 16.8에서 소개된 Hooks는 함수형 컴포넌트에서 상태 관리와 생명주기 기능을 사용할 수 있게 해주는 강력한 도구입니다. 이 포스트에서는 가장 자주 사용되는 세 가지 Hook인 useState
, useEffect
, useCallback
에 대해 자세히 알아보겠습니다.
목차
useState
useState
는 함수형 컴포넌트에서 상태를 관리할 수 있게 해주는 Hook입니다.
기본 구조
const [state, setState] = useState(initialState);
특징
- 컴포넌트에 지역 상태를 추가할 수 있습니다.
- 함수형 업데이트를 지원합니다:
setState(prevState => newState)
- 초기 상태는 한 번만 사용됩니다. 이후 렌더링에서는 무시됩니다.
예제
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
장점
- 간단하고 직관적인 API
- 클래스 컴포넌트의 this 바인딩 문제 해결
- 여러 상태를 쉽게 관리 가능
단점
- 복잡한 상태 로직을 관리하기 어려울 수 있음 (이 경우 useReducer 고려)
useEffect
useEffect
는 함수형 컴포넌트에서 side effects를 수행할 수 있게 해주는 Hook입니다.
기본 구조
useEffect(() => {
// side effect
return () => {
// cleanup
};
}, [dependencies]);
특징
- 컴포넌트 렌더링 이후에 실행됩니다.
- 의존성 배열을 통해 effect의 실행 조건을 제어할 수 있습니다.
- 클린업 함수를 반환하여 구독 해제 등의 정리 작업을 수행할 수 있습니다.
예제
function FriendStatus(props) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
}, [props.friend.id]);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
장점
- 생명주기 메서드를 대체하여 관련 로직을 한 곳에서 관리
- 불필요한 effect 실행을 방지할 수 있음
단점
- 의존성 배열 관리가 복잡할 수 있음
- 과도한 사용 시 성능 저하 가능성
useCallback
useCallback
은 메모이제이션된 콜백을 반환하는 Hook입니다.
기본 구조
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
특징
- 의존성이 변경되었을 때만 새로운 함수를 반환합니다.
- 불필요한 렌더링을 방지하는 데 도움이 됩니다.
예제
function ParentComponent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(c => c + 1);
}, []);
return (
<div>
<ChildComponent onIncrement={increment} />
<p>Count: {count}</p>
</div>
);
}
장점
- 불필요한 리렌더링 방지
- 성능 최적화에 도움
- useEffect의 의존성 최적화
단점
- 과도한 사용 시 코드 복잡성 증가
- 간단한 함수에 사용 시 오히려 성능 저하 가능성
종합 예제
다음은 세 가지 Hook을 모두 사용하는 예제입니다:
import React, { useState, useEffect, useCallback } from 'react';
function DataFetcher({ url }) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const fetchData = useCallback(async () => {
setLoading(true);
try {
const response = await fetch(url);
const result = await response.json();
setData(result);
} catch (error) {
console.error("Failed to fetch data:", error);
} finally {
setLoading(false);
}
}, [url]);
useEffect(() => {
fetchData();
}, [fetchData]);
return (
<div>
{loading ? (
<p>Loading...</p>
) : (
<pre>{JSON.stringify(data, null, 2)}</pre>
)}
<button onClick={fetchData}>Refresh Data</button>
</div>
);
}
export default DataFetcher;
이 예제에서:
useState
를 사용하여 데이터와 로딩 상태를 관리합니다.useCallback
을 사용하여fetchData
함수를 메모이제이션합니다.useEffect
를 사용하여 컴포넌트 마운트 시 데이터를 가져옵니다.
결론
useState
, useEffect
, useCallback
은 React 애플리케이션 개발에서 핵심적인 역할을 하는 Hook들입니다. 이들을 적절히 사용하면 컴포넌트의 상태 관리, 부수 효과 처리, 성능 최적화를 효과적으로 수행할 수 있습니다. 하지만 각 Hook의 특성과 사용 시 주의사항을 잘 이해하고 적절히 활용하는 것이 중요합니다.
React Hooks는 함수형 프로그래밍의 장점을 살리면서도 강력한 기능을 제공하여 React 개발을 더욱 효율적이고 직관적으로 만들어줍니다. 지속적인 학습과 실践을 통해 이러한 Hook들을 마스터한다면, 더 나은 React 애플리케이션을 개발할 수 있을 것입니다