
React를 처음 배우면서 다양한 개념이 마구마구 머릿속으로 들어오고 있는데,, Hook의 다양한 종류와 사용법에 대해서 배우면서 갑자기 많은 개념에 조금 당황했던 것 같다.
그래서 이번 시간에는 React의 Hook에 대해 언제, 왜, 어떻게 사용하는지를 입문자 입장에서 좀 더 쉽게 정리해보려고 한다!
Hook은 React 함수형 컴포넌트에서 상태(state)와 생명주기(lifecycle) 관련 기능을 사용할 수 있도록 도와주는 함수이다.
원래 상태 관리와 생명주기 메서드는 클래스형 컴포넌트에서만 가능했지만, React의 Hook을 사용하면 함수형 컴포넌트에서도 이를 구현할 수 있다!
this.state, this.setState() 등을 사용해야 하지만, Hook을 사용하면 useState로 간단하게 관리가 가능하다componentDidMount, componentDidUpdate, componentWillUnmoun 등의 생명주기 메서드를 사용해야 하지만, Hook을 사용하면 useEffect 하나로 처리 가능하다useState, useEffect, useRef, useMemo, useCallback 등이 있으며, 필요에 따라 Custom Hook을 직접 만들어서 활용할 수도 있다.✅ 언제?
✅ 왜?
useState를 사용하면 간단하게 상태를 선언하고 변경할 수 있음✅ 어떻게?
⚙️ 동작 방식
useState는 초기값을 전달하면 상태 변수와 그 값을 업데이트할 수 있는 함수를 반환한다.
상태값은 컴포넌트의 렌더링 사이에서 기억(저장)되며, 상태가 변경되면 컴포넌트는 다시 랜더링된다.
이 과정은 상태가 바뀌었을 때만 화면을 업데이트하여 최적화 렌더링을 보장한다
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0); // count 상태를 0으로 초기화
return (
<div>
<p>현재 카운트: {count}</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
✏️ 코드 설명
const [count, setCount] = useState(0);useState는 배열을 반환하며 첫 번째 요소는 현재 상태 값 (count), 두 번째 요소는 그 값을 업데이트하는 함수(setCount)이다<button onClick={() => setCount(count + 1)}>Click me</button>setCount 함수는 상태를 직접 변경하는 것이 아니라, 상태 업데이트 요청을 React에 전달한다.count값이 업데이트된 화면을 보여준다.🤔 부수 효과(side effect)란?
- 컴포넌트의 렌더링 외부에서 발생하는 모든 작업을 의미
- 예를 들어, API 요청, DOM 조작, 타이머 설정, 로컬 스토리지 저장 등은 렌더링 동안 바로 실행 될 수 없다.
- 주로 컴포넌트의 상태나 렌더링을 직접 변경하지 않지만, 그 결과로 다른 컴포넌트나 시스템에 영향을 미치는 작업들이다.
- React에서
useEffect는 이러한 부수 효과를 컴포넌트의 렌더링 후에 처리하게 해주며, 렌더링 중에는 실행되지 않도록 보장한다.
✅ 언제?
✅ 왜?
✅ 어떻게?
⚙️ 동작 방식
useEffect(이펙트 함수, 의존성 배열);- 렌더링 이후에 실행되며, 두 번째 인수로 의존성 배열을 전달하여 언제 재실행할지를 제어할 수 있다.
- 만약 의존성 배열 속 값이 하나라도 변경되면 이펙트 함수가 실행된다.
import { useState, useEffect } from "react";
function Timer() {
const [time, setTime] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setTime(prevTime => prevTime + 1);
}, 1000);
return () => clearInterval(timer); //컴포넌트가 사라질 때 인터벌 정리
}, []);
return <p>현재 시간: {time}</p>;
}
✏️ 코드 설명
useEffect(() => {...}, []);[]은 빈 배열로 설정되어 있기 때문에, 컴포넌트가 처음 마운트될 때만 실행된다. (최초 1회만 실행)return () => clearInterval(timer);clearInterval을 호출해서 타이머가 계속 실행되지 않도록 한다.✅ 언제?
✅ 왜?
useMemo를 사용하면 특정 값이 변경될 때만 연산을 실행하도록 할 수 있음✅ 어떻게?
⚙️ 동작 방식
- 함수가 비싼 계산을 반복하지 않도록 결과를 메모이제이션한다.
- 의존성 배열에 포함된 값이 변경될 때만 계산이 다시 실행되며, 나머지 경우엔 이전에 계산된 값을 재사용한다.
import { useMemo } from "react";
function ExpensiveComputation({ num }) {
const result = useMemo(() => {
console.log("계산 중...");
return num * 2; // 비싼 계산을 하는 코드
}, [num]); // num이 변경될 때만 재계산
return <p>결과: {result}</p>;
}
✏️ 코드 설명
const result = useMemo(() => { ... }, [num]);console.log("계산 중...");는 num이 변경될 때만 출력한다.✅ 언제?
✅ 왜?
useCallback을 사용하면 기존 함수를 재사용하여 성능을 향상시킬 수 있음✅ 어떻게?
⚙️ 동작 방식
useCallback은 함수를 메모이제이션 하여 동일한 함수 객체를 유지- 두 번째 인자로 주어진 의존성 배열의 값이 변경될 때만 새로운 함수 생성
- 함수가 필요할 때마다 새로 생성되지 않고, 이전 함수를 재사용하여 불필요한 리렌더링 방지
import { useState, useCallback } from "react";
function Parent() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log(count);
}, [count]); // count가 변경될 때만 함수 재생성
return <Child onClick={handleClick} />;
}
function Child({ onClick }) {
return <button onClick={onClick}>Click</button>;
}
✏️ 코드 설명
const handleClick = useCallback(() => {...}, [count]);count가 변경될 때만 함수를 재생성하고, 그 외의 경우에는 기존 함수를 재사용console.log(count);는 count가 변경될 때만 출력한다.✅ 언제?
✅ 왜?
useState를 사용하면 값이 변경될 때마다 리렌더링이 발생하지만, useRef는 렌더링 없이 값을 유지할 수 있기 때문✅ 어떻게?
⚙️ 동작 방식
.current속성을 가진 객체를 반환useRef의 값은 컴포넌트가 리렌더링되어도 유지되며, 값이 변경되어도 리렌더링이 발생하지 않음
import { useRef } from "react";
function InputFocus() {
const inputRef = useRef();
const handleClick = () => {
// inputRef.current는 DOM 요소를 가리키므로 focus() 호출 가능
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} />
<button onClick={handleClick}>Input Focus</button>
</div>
);
}
✏️ 코드 설명
| Hook | 역할 | 특징 | 언제 사용? |
|---|---|---|---|
useState | 상태 관리 | 값이 변경되면 리렌더링 발생 | 입력 값 관리, 버튼 클릭 시 값 변경 |
useEffect | 부수 효과 처리 | 렌더링 이후 특정 동작 실행 | API 호출, 이벤트 리스너 등록 |
useMemo | 연산 최적화 | 값 재계산 방지 | 복잡한 계산이 필요할 때 |
useCallback | 함수 최적화 | 함수 재생성 방지 | 자식 컴포넌트에 함수 전달 시 |
useRef | 렌더링 방지, DOM 조작 | 값이 변경되어도 리렌더링 안됨 | 포커스 제어, 이전 값 저장 |
이번 글을 통해서 Hook을 다시 정리하기 전까지는 각각의 Hook에 대해 개념은 배웠지만, 실제로 어떤 상황에서 어떤 Hook을 적용해야 하는지에 대한 감이 잘 오지 않았다.
하지만, 이번 정리를 통해 각 Hook의 동작 방식과 활용 방법을 보다 체계적으로 정리할 수 있었고, Hook의 사용에 대한 기본적 틀을 잡을 수 있었다.
앞으로 더 익숙해지기 위해서 강의 등을 통해 작은 서비스를 클론 코딩하면서 실전 감각을 키울 계획이다!
이번 글은 나 스스로 Hook을 이해하기에 중점을 두고 쓰다보니 글이 다소 길어진 감이 있다 ㅎ.. 이번 글이 Hook이 헷갈리면 언제든 다시 와서 확인할 수 있는 사전 처럼 활용하면 좋을 것 같다!