React Hooks 필수 요소: 깔끔하게 상태와 사이드 이펙트 관리하기
2024-09-25 15:01:48소개
리액트(React)는 JavaScript로 사용자 인터페이스를 구축하는데 유용한 라이브러리입니다. 리액트가 처음 등장했을 때만 하더라도 클래스 기반 구성 요소(Class Component)가 주를 이루고 있었습니다. 그러나 2019년 리액트 16.8 버전에서 도입된 훅(Hook)은 함수형 구성 요소(Function Component)에서도 상태(state)와 생명주기(lifecycle) 기능에 접근할 수 있도록 하여, 더욱 직관적이고 간결하게 컴포넌트를 설계할 수 있게 되었습니다. 이 글에서는 리액트 훅의 주요 요소와 활용법에 대해 심층적으로 다루어 보겠습니다.
배경 및 필요성
기존의 리액트에서는 상태 관리와 생명주기 관리를 위해 클래스 기반 구성 요소를 사용해야 했습니다. 이로 인해 컴포넌트와 상태 관리의 구조가 복잡해졌고, 코드의 중복이 발생하기도 하였습니다. 또한, 클래스 컴포넌트는 상태를 효과적으로 재사용하기 어렵고, 불필요한 복잡성을 야기했습니다. 이에 따라 리액트 팀은 훅을 도입하게 되었고, 이를 통해 다음과 같은 장점을 가지게 되었습니다:
-
코드의 간결함: 함수형 컴포넌트에서 직접 상태를 관리하고 사이드 이펙트를 처리할 수 있어 코드를 훨씬 간단하게 유지할 수 있습니다.
-
재사용성: 커스텀 훅(Custom Hook)을 통해 상태 있는 로직을 재사용할 수 있습니다. 덕분에 코드의 중복을 줄이고, 편리하게 상태를 공유할 수 있습니다.
-
기능의 강력함: 함수형 컴포넌트가 클래스 컴포넌트 못지않게 강력한 기능을 가질 수 있게 되어, 리액트 생태계에 더욱 일관성을 부여하게 되었습니다.
핵심 내용
리액트 훅의 핵심적인 요소는 다음과 같습니다:
useState
useState는 함수형 컴포넌트에서 상태를 관리하는 데 필수적인 훅입니다. 구조 분해 할당(destructuring assignment)을 통해 상태와 상태를 변경하는 함수를 선언합니다.
const [state, setState] = useState(initialState);
예를 들어, 카운터 컴포넌트를 만들어보겠습니다:
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
useEffect
useEffect 훅은 컴포넌트의 사이드 이펙트를 처리하는 데 사용됩니다. 데이터 fetching, DOM 업데이트, 이벤트 구독 등 다양한 작업을 관리할 수 있습니다.
useEffect(() => {
// 사이드 이펙트 로직
return () => {
// 정리 작업
};
}, [dependencies]);
다음은 API에서 데이터를 fetching하는 예입니다:
import React, { useState, useEffect } from "react";
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
fetch("https://api.example.com/data")
.then((response) => response.json())
.then((data) => setData(data));
}, []);
return <div>{data ? <p>{data.title}</p> : <p>Loading...</p>}</div>;
}
useReducer
useReducer 훅은 복잡한 상태 관리에 유용합니다. 상태를 액션 타입에 따라 업데이트하는데 사용되며, Redux와 유사하지만 컴포넌트 수준에서 작동합니다.
const [state, dispatch] = useReducer(reducer, initialState);
이 예시에서는 카운트를 증감하는 두 가지 액션을 처리합니다:
import React, { useReducer } from "react";
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
}
useRef
useRef 훅은 DOM 요소에 직접 접근하거나 렌더 간에 변경 가능한 값을 저장하는 데 사용됩니다.
const myRef = useRef(initialValue);
아래는 입력 필드에 직접 포커스를 주는 예시입니다:
import React, { useRef } from "react";
function InputFocus() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
Custom Hooks
커스텀 훅은 훅의 강력한 기능 중 하나입니다. use로 시작하며, 다른 훅을 활용하여 로직을 캡슐화하고 재사용할 수 있습니다. 예를 들어, 데이터 fetching을 처리하는 커스텀 훅은 다음과 같이 만들 수 있습니다:
import { useState, useEffect } from "react";
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url)
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
});
}, [url]);
return { data, loading };
}
예시
리액트를 처음 사용하는 개발자라면, 훅의 사용 방식을 이해하는 것이 중요합니다. 위에서 설명한 다양한 훅을 실제 프로젝트에 적용해보며 사용법을 익혀보세요. 또한 커스텀 훅을 생성하여 코드의 재사용성을 높이는 노력을 기울이는 것도 좋은 방법입니다. 리액트 훅을 통해 보다 가독성이 좋고 유지보수가 쉬운 코드를 작성할 수 있을 것입니다.
이제 리액트 훅이 무엇인지, 그리고 왜 필요한지를 이해하셨다면, 마음껏 활용하여 개발의 생산성을 높여보시기 바랍니다.