본문 바로가기
IT개발/TypeScript

[TypeScript] TypeScript 상태 관리 Hook 정리

by Thompson 2025. 5. 19.
728x90
반응형

1. useState

useState는 가장 기본적인 상태 관리 Hook으로, 컴포넌트 내에서 상태를 저장하고 업데이트하는 데 사용됩니다.

import { useState } from "react";

const Counter: React.FC = () => {
  const [count, setCount] = useState<number>(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

2. useEffect

useEffect는 컴포넌트가 렌더링될 때 특정 로직을 실행하고자 할 때 사용됩니다.

(예를 들면 API 호출, 구독(subscription), DOM 업데이트 등의 작업이 가능합니다.)

import { useState, useEffect } from "react";

const Timer: React.FC = () => {
  const [seconds, setSeconds] = useState<number>(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds((prev) => prev + 1);
    }, 1000);

    return () => clearInterval(interval); // cleanup 함수
  }, []);

  return <p>Seconds: {seconds}</p>;
};

3. useContext

useContext는 전역 상태를 관리할 때 사용되며, React.createContext와 함께 사용됩니다.

(전역 상태를 쉽게 공유할 수 있습니다.)

import { createContext, useContext, useState, ReactNode } from "react";

type ThemeContextType = {
  theme: string;
  setTheme: (theme: string) => void;
};

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

const ThemeProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const [theme, setTheme] = useState<string>("light");
  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

const ThemedComponent: React.FC = () => {
  const context = useContext(ThemeContext);
  if (!context) throw new Error("useContext must be used within a ThemeProvider");

  const { theme, setTheme } = context;
  return (
    <div>
      <p>Current Theme: {theme}</p>
      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        Toggle Theme
      </button>
    </div>
  );
};

4. useReducer

useReducer는 useState보다 복잡한 상태를 관리하는 데 유용합니다.

(보통 Redux 패턴과 유사한 형태로 상태를 업데이트할 수 있습니다.)

import { useReducer } from "react";

type State = { count: number };
type Action = { type: "increment" } | { type: "decrement" };

const initialState: State = { count: 0 };

const reducer = (state: State, action: Action): State => {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
};

const Counter: React.FC = () => {
  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>
  );
};

5. useRef

useRef는 DOM 요소에 접근하거나 컴포넌트가 리렌더링될 때 값이 유지되도록 하는 데 사용됩니다.

import { useRef, useEffect } from "react";

const InputFocus: React.FC = () => {
  const inputRef = useRef<HTMLInputElement | null>(null);

  useEffect(() => {
    inputRef.current?.focus();
  }, []);

  return <input ref={inputRef} type="text" placeholder="Focus here" />;
};

6. useMemo

useMemo는 성능 최적화를 위해 특정 연산을 캐싱할 때 사용됩니다.

import { useState, useMemo } from "react";

type ExpensiveCalculationProps = {
  num: number;
};

const ExpensiveCalculation: React.FC<ExpensiveCalculationProps> = ({ num }) => {
  const result = useMemo(() => {
    console.log("Calculating...");
    return num * 2;
  }, [num]);

  return <p>Result: {result}</p>;
};

7. useCallback

useCallback은 함수가 불필요하게 다시 생성되는 것을 방지하는 Hook입니다.

import { useState, useCallback } from "react";

type ChildComponentProps = {
  onClick: () => void;
};

const ChildComponent: React.FC<ChildComponentProps> = ({ onClick }) => {
  return <button onClick={onClick}>Click Me</button>;
};

const ParentComponent: React.FC = () => {
  const [count, setCount] = useState<number>(0);

  const handleClick = useCallback(() => {
    console.log("Button clicked!");
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <ChildComponent onClick={handleClick} />
    </div>
  );
};