Dev

React Hooks: useState, useEffect, useCallback

On this page

React 16.8에서 소개된 Hooks는 함수형 컴포넌트에서 상태 관리와 생명주기 기능을 사용할 수 있게 해주는 강력한 도구입니다. 이 포스트에서는 가장 자주 사용되는 세 가지 Hook인 useState, useEffect, useCallback에 대해 자세히 알아보겠습니다.

목차

  1. useState
  2. useEffect
  3. useCallback
  4. 종합 예제
  5. 결론

useState

useState는 함수형 컴포넌트에서 상태를 관리할 수 있게 해주는 Hook입니다.

기본 구조

const [state, setState] = useState(initialState);

특징

  • 컴포넌트에 지역 상태를 추가할 수 있습니다.
  • 함수형 업데이트를 지원합니다: setState(prevState => newState)
  • 초기 상태는 한 번만 사용됩니다. 이후 렌더링에서는 무시됩니다.

예제

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

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

장점

  • 간단하고 직관적인 API
  • 클래스 컴포넌트의 this 바인딩 문제 해결
  • 여러 상태를 쉽게 관리 가능

단점

  • 복잡한 상태 로직을 관리하기 어려울 수 있음 (이 경우 useReducer 고려)

useEffect

useEffect는 함수형 컴포넌트에서 side effects를 수행할 수 있게 해주는 Hook입니다.

기본 구조

useEffect(() => {
// side effect
  return () => {
// cleanup
  };
}, [dependencies]);

특징

  • 컴포넌트 렌더링 이후에 실행됩니다.
  • 의존성 배열을 통해 effect의 실행 조건을 제어할 수 있습니다.
  • 클린업 함수를 반환하여 구독 해제 등의 정리 작업을 수행할 수 있습니다.

예제

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);

    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  }, [props.friend.id]);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

장점

  • 생명주기 메서드를 대체하여 관련 로직을 한 곳에서 관리
  • 불필요한 effect 실행을 방지할 수 있음

단점

  • 의존성 배열 관리가 복잡할 수 있음
  • 과도한 사용 시 성능 저하 가능성

useCallback

useCallback은 메모이제이션된 콜백을 반환하는 Hook입니다.

기본 구조

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

특징

  • 의존성이 변경되었을 때만 새로운 함수를 반환합니다.
  • 불필요한 렌더링을 방지하는 데 도움이 됩니다.

예제

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

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

  return (
    <div>
      <ChildComponent onIncrement={increment} />
      <p>Count: {count}</p>
    </div>
  );
}

장점

  • 불필요한 리렌더링 방지
  • 성능 최적화에 도움
  • useEffect의 의존성 최적화

단점

  • 과도한 사용 시 코드 복잡성 증가
  • 간단한 함수에 사용 시 오히려 성능 저하 가능성

종합 예제

다음은 세 가지 Hook을 모두 사용하는 예제입니다:

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

function DataFetcher({ url }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  const fetchData = useCallback(async () => {
    setLoading(true);
    try {
      const response = await fetch(url);
      const result = await response.json();
      setData(result);
    } catch (error) {
      console.error("Failed to fetch data:", error);
    } finally {
      setLoading(false);
    }
  }, [url]);

  useEffect(() => {
    fetchData();
  }, [fetchData]);

  return (
    <div>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <pre>{JSON.stringify(data, null, 2)}</pre>
      )}
      <button onClick={fetchData}>Refresh Data</button>
    </div>
  );
}

export default DataFetcher;

이 예제에서:

  • useState를 사용하여 데이터와 로딩 상태를 관리합니다.
  • useCallback을 사용하여 fetchData 함수를 메모이제이션합니다.
  • useEffect를 사용하여 컴포넌트 마운트 시 데이터를 가져옵니다.

결론

useState, useEffect, useCallback은 React 애플리케이션 개발에서 핵심적인 역할을 하는 Hook들입니다. 이들을 적절히 사용하면 컴포넌트의 상태 관리, 부수 효과 처리, 성능 최적화를 효과적으로 수행할 수 있습니다. 하지만 각 Hook의 특성과 사용 시 주의사항을 잘 이해하고 적절히 활용하는 것이 중요합니다.

React Hooks는 함수형 프로그래밍의 장점을 살리면서도 강력한 기능을 제공하여 React 개발을 더욱 효율적이고 직관적으로 만들어줍니다. 지속적인 학습과 실践을 통해 이러한 Hook들을 마스터한다면, 더 나은 React 애플리케이션을 개발할 수 있을 것입니다

Subscribe to Keun's Story newsletter and stay updated.

Don't miss anything. Get all the latest posts delivered straight to your inbox. It's free!
Great! Check your inbox and click the link to confirm your subscription.
Error! Please enter a valid email address!