React Hooks 가이드: 효율적인 컴포넌트 만들기

React는 16.8 버전부터 Hooks라는 새로운 기능을 도입하여 함수형 컴포넌트에서도 상태 관리와 라이프사이클 메서드를 사용할 수 있게 했습니다.

이 글에서는 React Hooks의 기본 개념부터 고급 사용법까지 깊이 있게 다루고, 이를 활용해 효율적인 컴포넌트를 만드는 방법을 설명하겠습니다.

  1. React Hooks란 무엇인가?
  2. 기본 Hooks
    • useState
    • useEffect
    • useContext
  3. 추가 Hooks
    • useReducer
    • useCallback
    • useMemo
    • useRef
    • useLayoutEffect
  4. 커스텀 Hooks 만들기
  5. Hooks 사용 시 유의할 점
  6. 결론

React Hooks는 클래스형 컴포넌트에서만 사용할 수 있었던 상태 관리와 라이프사이클 메서드를 함수형 컴포넌트에서도 사용할 수 있게 해주는 기능입니다.

이를 통해 코드가 더 간결해지고, 로직을 재사용하기 쉬워집니다.

useState는 상태 변수를 선언하고 이를 업데이트할 수 있는 함수를 반환합니다.

import React, { useState } from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

useEffect는 사이드 이펙트를 수행할 수 있도록 해주는 Hook입니다. 예를 들어, 데이터 페칭, 구독, 수동으로 DOM을 변경하는 작업 등을 처리할 수 있습니다.

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

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

useContext는 Context API를 더 간편하게 사용할 수 있도록 해줍니다.

import React, { useContext } from 'react';

const ThemeContext = React.createContext('light');

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return <button className={theme}>I am styled by theme context!</button>;
}

useReducer는 상태 관리 로직을 컴포넌트에서 분리할 수 있도록 도와줍니다. Redux와 비슷한 패턴을 따릅니다.

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:
      throw new Error();
  }
}

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>
  );
}

useCallback은 메모이제이션된 콜백을 반환합니다. 이 Hook은 컴포넌트가 불필요하게 다시 렌더링되는 것을 방지하는 데 유용합니다.

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

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

  const increment = useCallback(() => {
    setCount(count + 1);
  }, [count]);

  return <Child increment={increment} />;
}

function Child({ increment }) {
  return <button onClick={increment}>Increment</button>;
}

useMemo는 메모이제이션된 값을 반환합니다. 이 Hook은 연산 비용이 높은 계산을 최적화하는 데 유용합니다.

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

function ExpensiveComponent({ a, b }) {
  const memoizedValue = useMemo(() => a + b, [a, b]);
  return <div>{memoizedValue}</div>;
}

useRef는 변경 가능한 참조 객체를 생성합니다. 이 객체는 컴포넌트의 생애주기 동안 유지됩니다.

import React, { useRef } from 'react';

function TextInputWithFocusButton() {
  const inputEl = useRef(null);

  const onButtonClick = () => {
    inputEl.current.focus();
  };

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

useLayoutEffect는 브라우저가 화면을 그리기 전에 동기적으로 실행됩니다. 이는 useEffect와 달리 레이아웃 측정 및 DOM 조작에 유용합니다.

import React, { useLayoutEffect, useRef } from 'react';

function LayoutEffectExample() {
  const ref = useRef();

  useLayoutEffect(() => {
    console.log(ref.current.getBoundingClientRect());
  }, []);

  return <div ref={ref}>Hello, world!</div>;
}

커스텀 Hook은 반복되는 로직을 재사용할 수 있게 해줍니다. 예를 들어, 윈도우 사이즈를 추적하는 커스텀 Hook을 만들 수 있습니다.

import { useState, useEffect } from 'react';

function useWindowSize() {
  const [size, setSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    const handleResize = () => {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return size;
}

function App() {
  const size = useWindowSize();
  return (
    <div>
      <p>Width: {size.width}</p>
      <p>Height: {size.height}</p>
    </div>
  );
}

Hook은 최상위 레벨에서만 호출 – Hook은 컴포넌트의 최상위 레벨에서만 호출해야 합니다. 루프, 조건문, 중첩된 함수 내에서 호출하지 않습니다.

React 함수형 컴포넌트에서만 사용 – Hook은 함수형 컴포넌트나 커스텀 Hook 내에서만 호출해야 합니다.

의존성 배열 관리 – useEffect, useCallback, useMemo등을 사용할 때 의존성 배열을 정확히 관리해야 합니다. 이를 통해 의도하지 않은 재렌더링을 방지할 수 있습니다.

React Hooks는 컴포넌트를 더 간결하고 이해하기 쉽게 만들며, 상태 관리와 부수 효과를 함수형 컴포넌트에서 처리할 수 있도록 해줍니다. 기본 Hooks에서부터 커스텀 Hooks까지 다양한 사용법을 익히고, 이를 통해 효율적이고 재사용 가능한 컴포넌트를 만들어보세요.

이 가이드가 React Hooks를 이해하고 활용하는 데 도움이 되길 바랍니다.

    Loading

    Leave a Reply

    Your email address will not be published. Required fields are marked *