400===Dev Library/React

React Hooks(리액트 훅) 완벽 정리 😋

블로글러 2024. 6. 23. 16:13

React Hooks는 함수형 컴포넌트에서 상태 관리와 생명주기 메서드를 사용할 수 있게 해주는 기능입니다. React 16.8에서 도입되었으며, 클래스 컴포넌트 없이도 React의 다양한 기능을 활용할 수 있게 해줍니다. 주요 훅으로는 useState, useEffect, useContext, useMemo, useCallback이 있으며, 개발자가 직접 커스텀 훅을 만들어 컴포넌트 로직을 재사용할 수도 있습니다.

오늘은 React 개발을 더 쉽고 효율적으로 만들어주는 React Hooks에 대해 알아보겠습니다!

React Hooks가 뭔가요? 🤔

여러분의 집에 다양한 스마트 기기들이 있다고 상상해보세요.

  • 스마트 메모장은 중요한 정보를 기억합니다
  • 스마트 비서는 특정 이벤트가 발생할 때 작업을 수행합니다
  • 스마트 스피커는 집 전체에 정보를 공유합니다

React Hooks가 바로 이런 역할을 합니다!

  • 함수형 컴포넌트에 다양한 기능을 쉽게 추가해주는 특별한 함수들
  • 클래스 컴포넌트 없이도 React의 모든 기능을 사용할 수 있게 해주는 마법 ✨

어떻게 동작하나요? 🎬

1. useState - 스마트 메모장

import React, { useState } from 'react';

function Counter() {
  // [현재값, 업데이트함수] = useState(초기값)
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>현재 카운트: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        증가
      </button>
    </div>
  );
}

2. useEffect - 스마트 비서

import React, { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  // 컴포넌트가 렌더링된 후 실행됩니다
  useEffect(() => {
    // API에서 사용자 데이터 가져오기
    fetch(`https://api.example.com/users/${userId}`)
      .then(response => response.json())
      .then(data => setUser(data));

    // 컴포넌트가 언마운트될 때 정리 작업 수행
    return () => {
      console.log('컴포넌트 정리 중...');
    };
  }, [userId]); // userId가 변경될 때만 실행

  if (!user) return <div>로딩 중...</div>;

  return <div>{user.name}의 프로필</div>;
}

3. useContext - 스마트 스피커

import React, { useContext } from 'react';

// 컨텍스트 생성
const ThemeContext = React.createContext('light');

function App() {
  // 상위 컴포넌트에서 컨텍스트 제공
  return (
    <ThemeContext.Provider value="dark">
      <ThemedButton />
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  // 하위 컴포넌트에서 컨텍스트 사용
  const theme = useContext(ThemeContext);

  return <button className={theme}>테마 적용 버튼</button>;
}

4. useMemo - 스마트 계산기

import React, { useState, useMemo } from 'react';

function ExpensiveCalculation({ numbers }) {
  // 복잡한 계산은 dependencies가 변경될 때만 재실행됩니다
  const sum = useMemo(() => {
    console.log('복잡한 계산 수행 중...');
    return numbers.reduce((total, num) => total + num, 0);
  }, [numbers]); // numbers가 변경될 때만 다시 계산

  return <div>계산 결과: {sum}</div>;
}

5. useCallback - 스마트 리모컨

import React, { useState, useCallback } from 'react';

function ParentComponent() {
  const [count, setCount] = useState(0);

  // 메모이제이션된 함수를 생성합니다
  const handleClick = useCallback(() => {
    console.log('버튼 클릭!');
    setCount(prevCount => prevCount + 1);
  }, []); // 의존성 배열이 비어있으므로 함수는 한 번만 생성됩니다

  return (
    <div>
      <p>카운트: {count}</p>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

function ChildComponent({ onClick }) {
  console.log('자식 컴포넌트 렌더링');
  return <button onClick={onClick}>클릭</button>;
}

장점은? 🌟

  1. 코드가 간결해져요

    • 클래스 컴포넌트의 복잡한 생명주기 메서드 대신 직관적인 함수 사용
    • this 바인딩 문제에서 해방!
  2. 로직 재사용이 쉬워요

    • 커스텀 훅으로 컴포넌트 로직을 추출하여 재사용 가능
    • 마치 레고 블록처럼 기능을 조립할 수 있어요
  3. 성능 최적화가 간편해요

    • useMemo와 useCallback으로 불필요한 계산과 렌더링 방지
    • 코드 품질과 앱 성능 향상
  4. 테스트가 더 쉬워졌어요

    • 순수 함수 형태로 로직을 분리할 수 있어 테스트 용이
    • 의존성 주입이 더 명확해짐

주의할 점 ⚠️

  1. 규칙을 지켜야 해요

    • 훅은 항상 함수 컴포넌트의 최상위 레벨에서만 호출해야 함
    • 조건문, 반복문, 중첩 함수 내에서 호출하면 안 됨
  2. 의존성 배열을 올바르게 설정하세요

    • useEffect, useMemo, useCallback의 의존성 배열을 잘못 설정하면 버그 발생
    • 빈 배열([])은 "마운트와 언마운트에만 실행"을 의미
  3. 너무 많은 상태는 관리하기 어려워요

    • 복잡한 상태는 useReducer나 Context API와 함께 사용하는 것이 좋음
    • 상태 관리 라이브러리(Redux, Recoil 등)도 고려해보세요

실제 사용 예시 📱

커스텀 훅 만들기

// 폼 입력 관리를 위한 커스텀 훅
function useInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  // 입력 핸들러
  const handleChange = (e) => {
    setValue(e.target.value);
  };

  // 입력값 초기화
  const reset = () => {
    setValue(initialValue);
  };

  // 값과 핸들러를 객체로 반환
  return {
    value,
    onChange: handleChange,
    reset
  };
}

// 커스텀 훅 사용 예시
function SignupForm() {
  const name = useInput('');
  const email = useInput('');

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('제출된 데이터:', name.value, email.value);
    name.reset();
    email.reset();
  };

  return (
    <form onSubmit={handleSubmit}>
      <input placeholder="이름" {...name} />
      <input placeholder="이메일" type="email" {...email} />
      <button type="submit">가입하기</button>
    </form>
  );
}

로컬 스토리지와 함께 사용하기

// 로컬 스토리지와 연동하는 커스텀 훅
function useLocalStorage(key, initialValue) {
  // 초기 상태 설정
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // 로컬 스토리지에서 값 가져오기
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  // 값 설정 및 로컬 스토리지 업데이트
  const setValue = value => {
    try {
      // 함수인 경우 현재 상태를 인자로 전달
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      setStoredValue(valueToStore);
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
    } catch (error) {
      console.error(error);
    }
  };

  return [storedValue, setValue];
}

// 사용 예시
function DarkModeToggle() {
  const [darkMode, setDarkMode] = useLocalStorage('darkMode', false);

  return (
    <div className={darkMode ? 'dark' : 'light'}>
      <button onClick={() => setDarkMode(!darkMode)}>
        {darkMode ? '라이트 모드로 전환' : '다크 모드로 전환'}
      </button>
    </div>
  );
}

마치며 🎁

React Hooks는 마치 여러분의 집에 있는 스마트 기기들처럼 React 개발을 더 쉽고 효율적으로 만들어줍니다. 클래스 컴포넌트의 복잡함에서 벗어나 더 직관적이고 재사용 가능한 코드를 작성할 수 있습니다. 초보자부터 전문가까지 누구나 활용할 수 있는 강력한 기능이니, 꼭 한번 시도해보세요!


궁금하신 점 있으시다면 댓글로 남겨주세요! 😊

참고 자료

  1. React 공식 문서 - Hooks API 참조: https://legacy.reactjs.org/docs/hooks-reference.html
  2. freeCodeCamp - React Hooks 사용 방법: https://www.freecodecamp.org/news/react-hooks-useeffect-usestate-and-usecontext/
  3. Walturn Insight - React Hooks 소개: https://www.walturn.com/insights/introduction-to-hooks-in-react
  4. W3Schools - React useMemo Hook: https://www.w3schools.com/react/react_usememo.asp
  5. React 공식 문서 - useCallback: https://react.dev/reference/react/useCallback
728x90