React는 현재 가장 인기 있는 프론트엔드 라이브러리 중 하나로, 컴포넌트 기반 아키텍처와 가상 DOM을 통해 효율적인 UI 개발을 지원합니다. React의 가장 큰 장점 중 하나는 상태 관리(State Management)인데, 이를 효과적으로 다루기 위해 React Hook을 활용하는 방법에 대해 알아보겠습니다.
React Hook의 이해
React Hook은 함수형 컴포넌트에서 상태와 생명주기 기능을 사용할 수 있게 해주는 기능입니다. Hook을 사용하면 클래스형 컴포넌트에서만 지원되던 기능을 함수형 컴포넌트에서도 손쉽게 이용할 수 있습니다. useState, useEffect, useContext 등의 Hook을 활용하여 상태를 관리하고, 컴포넌트의 생명주기를 제어할 수 있습니다.
useState 사용 예제
가장 기본적인 상태 관리 Hook인 useState를 통해 컴포넌트의 상태를 관리하는 방법을 살펴보겠습니다.
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>증가</button>
<button onClick={() => setCount(count - 1)}>감소</button>
</div>
);
};
export default Counter;
위 코드에서는 useState를 사용하여 카운터의 값을 관리하고 있습니다. count는 현재 카운터 값을 나타내며, setCount는 이를 업데이트하는 함수입니다. 버튼 클릭 시 setCount를 호출하여 상태를 변경하고, 변경된 상태에 따라 UI가 자동으로 리렌더링됩니다.
useEffect로 사이드 이펙트 관리하기
useEffect는 컴포넌트가 렌더링된 후 특정 작업을 수행할 수 있도록 해주는 Hook입니다. 주로 API 호출이나 구독, 타이머 설정 등에서 사용됩니다. 아래는 useEffect를 활용한 API 호출 예제입니다.
import React, { useState, useEffect } from 'react';
const UserList = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
const fetchData = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const result = await response.json();
setUsers(result);
};
fetchData();
}, []); // 빈 배열을 넘겨주면 컴포넌트가 마운트될 때만 실행됩니다.
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default UserList;
위 예제에서 useEffect는 컴포넌트가 마운트될 때 한 번만 호출되어 API를 통해 사용자 목록을 가져옵니다. API 호출이 완료되면 setUsers를 통해 상태를 업데이트하고, 이를 통해 사용자 목록이 UI에 반영됩니다.
상태 관리 라이브러리와 Hook의 결합
React Hook을 사용하면 상태 관리 라이브러리를 필요로 하지 않는 간단한 상태 관리가 가능합니다. 그러나 애플리케이션의 상태가 복잡해질 경우에는 전역 상태 관리 라이브러리와 Hook을 결합하여 사용할 수 있습니다. 예를 들어, useContext와 useReducer를 활용하여 상태를 전역적으로 관리하는 방법을 살펴보겠습니다.
import React, { createContext, useReducer, useContext } from 'react';
// 초기 상태
const initialState = { count: 0 };
// 리듀서 함수
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
// 컨텍스트 생성
const CountContext = createContext();
// Provider 컴포넌트
const CountProvider = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<CountContext.Provider value={{ state, dispatch }}>
{children}
</CountContext.Provider>
);
};
// 카운터 컴포넌트
const Counter = () => {
const { state, dispatch } = useContext(CountContext);
return (
<div>
<h1>{state.count}</h1>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>증가</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>감소</button>
</div>
);
};
// App 컴포넌트
const App = () => (
<CountProvider>
<Counter />
</CountProvider>
);
export default App;
위 코드는 useReducer와 useContext를 활용하여 전역 상태를 관리하는 방법을 보여줍니다. CountProvider를 통해 하위 컴포넌트에서 상태와 dispatch 함수를 사용할 수 있습니다.
마무리
React Hook을 활용한 상태 관리는 함수형 컴포넌트의 장점을 극대화하고, 코드의 가독성과 유지 관리성을 높이는 데 기여합니다. 기본적인 상태 관리부터 시작해, useEffect를 통한 API 호출이나 전역 상태 관리까지 다양한 방법으로 React Hook을 활용할 수 있습니다. 이러한 기법들은 더 나아가 복잡한 애플리케이션에서도 효과적으로 상태를 관리하는 데 도움을 줄 것입니다. React의 매력을 한층 더 느껴보시기 바랍니다.