Hooks를 사용하면 컴포넌트에서 다양한 React 기능들을 사용할 수 있어요. React에서 기본으로 제공하는 내장 Hooks를 그대로 사용할 수도 있고, 이것들을 조합해서 나만의 커스텀 Hook을 만들 수도 있어요. 이 페이지에서는 React에 내장된 모든 Hooks를 나열하고 있어요.
State는 컴포넌트가 사용자 입력 같은 정보를 "기억"할 수 있게 해줘요. 예를 들어, 폼(form) 컴포넌트는 state를 사용해서 입력값을 저장할 수 있고, 이미지 갤러리 컴포넌트는 state를 사용해서 현재 선택된 이미지의 인덱스를 저장할 수 있어요.
컴포넌트에 state를 추가하려면, 다음 Hooks 중 하나를 사용하면 돼요:
useState는 직접 업데이트할 수 있는 state 변수를 선언해요.useReducer는 reducer 함수 안에 업데이트 로직을 담은 state 변수를 선언해요.💡 부연 설명:
useState는 간단한 상태를 관리할 때 쓰고,useReducer는 상태 업데이트 로직이 복잡하거나 여러 개의 하위 값을 다뤄야 할 때 유용해요. Redux의 reducer 패턴과 비슷하다고 생각하면 이해하기 쉬워요.
// ImageGallery 컴포넌트 예시
function ImageGallery() {
const [index, setIndex] = useState(0);
// ...
Context는 컴포넌트가 props로 전달하지 않고도 멀리 떨어진 부모 컴포넌트로부터 정보를 받을 수 있게 해줘요. 예를 들어, 앱의 최상위 컴포넌트가 현재 UI 테마를 그 아래에 있는 모든 컴포넌트에 전달할 수 있는데, 아무리 깊이 중첩되어 있어도 상관없어요.
💡 부연 설명: 보통 props를 통해 데이터를 전달하면, 중간에 있는 컴포넌트들이 해당 데이터를 사용하지 않더라도 계속 넘겨줘야 하는 "props drilling" 문제가 생기는데, Context를 사용하면 이 문제를 깔끔하게 해결할 수 있어요.
useContext는 context를 읽고 구독(subscribe)해요.// Button 컴포넌트 예시
function Button() {
const theme = useContext(ThemeContext);
// ...
Refs는 컴포넌트가 렌더링에 사용되지 않는 정보를 보관할 수 있게 해줘요. 예를 들어 DOM 노드라든가 타임아웃 ID 같은 것들이요. state와 달리, ref를 업데이트해도 컴포넌트가 다시 렌더링되지 않아요. Refs는 React 패러다임에서 벗어나는 일종의 "탈출구(escape hatch)"예요. 브라우저 내장 API 같은 React가 아닌 시스템과 작업해야 할 때 유용해요.
💡 부연 설명: ref는
.current프로퍼티를 가진 객체인데, 이 값을 자유롭게 읽고 쓸 수 있어요. state를 변경하면 리렌더링이 발생하지만, ref를 변경하면 리렌더링이 일어나지 않기 때문에, 렌더링과 무관한 값을 저장할 때 딱 좋아요.
useRef는 ref를 선언해요. 어떤 값이든 담을 수 있지만, 대부분 DOM 노드를 담는 데 사용돼요.useImperativeHandle은 컴포넌트가 노출하는 ref를 커스터마이즈할 수 있게 해줘요. 이건 거의 사용되지 않아요.// Form 컴포넌트 예시
function Form() {
const inputRef = useRef(null);
// ...
Effects는 컴포넌트가 외부 시스템에 연결하고 동기화할 수 있게 해줘요. 여기에는 네트워크, 브라우저 DOM, 애니메이션, 다른 UI 라이브러리로 작성된 위젯, 그리고 기타 React가 아닌 코드를 다루는 것이 포함돼요.
useEffect는 컴포넌트를 외부 시스템에 연결해요.// ChatRoom 컴포넌트 예시
function ChatRoom({ roomId }) {
useEffect(() => {
const connection = createConnection(roomId);
connection.connect();
return () => connection.disconnect();
}, [roomId]);
// ...
Effects는 React 패러다임에서 벗어나는 "탈출구(escape hatch)"예요. 애플리케이션의 데이터 흐름을 조율하는 데 Effects를 사용하지 마세요. 만약 외부 시스템과 상호작용하는 게 아니라면, Effect가 필요 없을 수도 있어요.
💡 부연 설명: 초보자들이 흔히 하는 실수 중 하나가 데이터 페칭이나 state 동기화 같은 걸 전부
useEffect로 처리하는 건데요, 꼭 필요한 경우가 아니면 Effect 없이 해결할 수 있는 방법을 먼저 고려해보는 게 좋아요.
useEffect에는 실행 타이밍이 다른, 잘 사용되지 않는 두 가지 변형이 있어요:
useLayoutEffect는 브라우저가 화면을 다시 그리기(repaint) 전에 실행돼요. 여기서 레이아웃을 측정할 수 있어요.useInsertionEffect는 React가 DOM에 변경을 가하기 전에 실행돼요. 라이브러리에서 동적 CSS를 삽입하는 데 사용할 수 있어요.또한 이벤트를 Effects로부터 분리할 수도 있어요:
useEffectEvent는 어떤 Effect Hook에서든 발생시킬 수 있는 비반응형(non-reactive) 이벤트를 만들어요.리렌더링 성능을 최적화하는 일반적인 방법은 불필요한 작업을 건너뛰는 거예요. 예를 들어, React에게 캐시된 계산 결과를 재사용하라고 알려주거나, 이전 렌더링 이후 데이터가 변경되지 않았다면 리렌더링을 건너뛰라고 알려줄 수 있어요.
계산과 불필요한 리렌더링을 건너뛰려면, 다음 Hooks 중 하나를 사용하세요:
useMemo는 비용이 많이 드는 계산의 결과를 캐시할 수 있게 해줘요.useCallback은 최적화된 컴포넌트에 전달하기 전에 함수 정의를 캐시할 수 있게 해줘요.💡 부연 설명:
useMemo는 값을 메모이제이션하고,useCallback은 함수를 메모이제이션한다고 생각하면 쉬워요. 둘 다 의존성 배열(dependency array)에 있는 값이 변경되지 않으면 이전에 캐시한 결과를 그대로 반환해요.
// TodoList 컴포넌트 예시
function TodoList({ todos, tab, theme }) {
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
// ...
}
때로는 화면이 실제로 업데이트되어야 하기 때문에 리렌더링을 건너뛸 수 없는 경우도 있어요. 그런 경우에는, 반드시 동기적이어야 하는 차단(blocking) 업데이트(예: 입력 필드에 타이핑하는 것)와 사용자 인터페이스를 차단할 필요가 없는 비차단(non-blocking) 업데이트(예: 차트 업데이트)를 분리해서 성능을 향상시킬 수 있어요.
렌더링의 우선순위를 정하려면, 다음 Hooks 중 하나를 사용하세요:
useTransition은 state 전환을 비차단(non-blocking)으로 표시하고, 다른 업데이트가 이를 중단할 수 있도록 해줘요.useDeferredValue는 UI의 중요하지 않은 부분의 업데이트를 지연시키고, 다른 부분이 먼저 업데이트되도록 해줘요.💡 부연 설명:
useTransition과useDeferredValue는 React 18에서 도입된 동시성(Concurrent) 기능이에요. 무거운 렌더링 작업이 있을 때 사용자 경험을 매끄럽게 유지하는 데 아주 유용해요. 예를 들어 검색어를 입력할 때 입력 자체는 즉시 반영하면서, 검색 결과 목록의 렌더링은 뒤로 미루는 식으로 활용할 수 있어요.
이 Hooks들은 주로 라이브러리 작성자에게 유용하고, 일반적인 애플리케이션 코드에서는 잘 사용되지 않아요.
useDebugValue는 React DevTools에서 여러분의 커스텀 Hook에 표시되는 라벨을 커스터마이즈할 수 있게 해줘요.useId는 컴포넌트가 고유한 ID를 자기 자신과 연결할 수 있게 해줘요. 보통 접근성(accessibility) API와 함께 사용돼요.useSyncExternalStore는 컴포넌트가 외부 스토어를 구독할 수 있게 해줘요.useActionState는 액션의 state를 관리할 수 있게 해줘요.JavaScript 함수로 나만의 커스텀 Hooks를 정의할 수도 있어요.
💡 부연 설명: 커스텀 Hook은
use로 시작하는 함수 이름을 가져야 해요 (예:useWindowSize,useFetch). 이렇게 하면 React가 해당 함수 안에서 Hook 규칙이 지켜지고 있는지 자동으로 검사할 수 있어요. 여러 컴포넌트에서 반복되는 로직이 있다면, 커스텀 Hook으로 추출해서 재사용하는 게 아주 좋은 패턴이에요!