Published On

React hooks - useEffect


useEffectReact의 부수 효과 관리 훅 중 하나입니다. 이 훅은 컴포넌트가 렌더링된 이후에 특정 작업을 수행할 수 있도록 도와줍니다. 서버에서 데이터를 가져오거나, 구독(subscribe) 설정 및 DOM 업데이트와 같은 작업에 자주 사용됩니다.

이 글에서는 useEffect의 사용법, 동작 원리, 그리고 주의사항을 자세히 알아봅니다.


useEffect의 정의와 기본 문법

useEffect컴포넌트의 라이프사이클에 반응하는 작업을 수행하기 위해 사용됩니다.

useEffect(() => {
  // 수행할 작업
  // ex) console.log(dependency)
}, [dependency]);
  • 첫 번째 인자: 수행할 작업을 정의한 함수입니다.
  • 두 번째 인자: 의존성 배열(dependency array)로, 이 배열에 포함된 값이 변경될 때만 해당 작업이 수행됩니다. 의존성 배열을 생략하면 매번 렌더링될 때마다 작업이 실행됩니다.

useEffect의 동작 원리

  • 초기 렌더링: 컴포넌트가 처음 렌더링된 이후, useEffect 내 작업이 실행됩니다.
  • 의존성 변경 감지: 의존성 배열에 포함된 값이 변경될 때마다 작업이 다시 실행됩니다.
  • 정리 함수(cleanup): useEffect는 컴포넌트가 언마운트되거나, 의존성이 변경될 때 정리 작업을 수행합니다.

정리 함수 사용하기

useEffect(() => {
  const subscription = someAPI.subscribe();

  return () => {
    // 정리 작업 수행
    subscription.unsubscribe();
  };
}, []);
  • 정리 함수는 첫 번째 인자로 전달된 함수 내에서 return 키워드를 사용해 정의합니다.
  • 예를 들어, 구독(subscribe) 해제 또는 타이머 제거와 같은 작업을 수행합니다.

의존성 배열 사용 시 주의사항

  • 의존성 배열에 포함된 모든 값은 참조 무결성을 유지해야 합니다. 즉, 상태나 props가 의존성 배열에 포함되어야 합니다.
  • 만약 의존성 배열을 생략하면 매 렌더링마다 작업이 실행됩니다.
//두번째 인자를 사용하지 않으면 매 렌더링마다 작업이 실행
useEffect(() => {
  console.log("항상 실행됩니다");
});

비동기 작업과 useEffect

useEffect 훅 내부에서는 비동기 작업을 자주 수행하게 됩니다.

예를 들어 API 호출이나 데이터베이스 조회, 타이머 설정 등과 같은 작업이 해당됩니다.

하지만, useEffect에서 비동기 작업을 수행할 때 몇 가지 주의사항이 필요합니다.

왜 useEffect에서 async 함수를 직접 사용할 수 없는가?

useEffect의 첫 번째 인자는 비동기 함수가 아닌 동기 함수여야 합니다.

만약 첫 번째 인자를 async 함수로 선언하면, 이 함수가 Promise를 반환합니다.

이는 useEffect가 기대하는 함수의 반환값(정리 함수와 같은 동기 함수)과 맞지 않기 때문에 오류를 발생시킬 수 있습니다.

// ❌ 이렇게 사용하면 안 됩니다.
useEffect(async () => {
  const data = await fetch("https://api.example.com/data");
  console.log(data);
}, []);

위 코드처럼 직접적으로 async 함수를 전달하면 React는 함수의 반환값을 정리(cleanup) 함수로 인식하고 문제가 발생할 수 있습니다.

비동기 작업을 처리하는 올바른 방법

useEffect 내에서는 비동기 함수를 내부에 선언한 뒤 호출하는 방식으로 비동기 작업을 수행합니다.

useEffect(() => {
  // 비동기 함수를 선언합니다.
  const fetchData = async () => {
    try {
      const response = await fetch("https://api.example.com/data");
      const result = await response.json();
      console.log(result);
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };

  // 선언한 비동기 함수를 호출합니다.
  fetchData();
}, []);
  • 비동기 함수(fetchData)를 useEffect 내부에서 선언합니다.
  • 비동기 함수를 선언한 후 즉시 호출합니다.
  • try-catch 구문을 사용하여 에러 처리를 수행합니다.

useEffect와 useLayoutEffect의 차이

항목useEffectuseLayoutEffect
실행 시점렌더링 후에 실행렌더링 직후, DOM이 그려지기 전에 실행
사용 예비동기 작업, API 호출DOM 조작이 필요한 작업
블로킹 여부비동기적으로 실행되어 블로킹되지 않음렌더링을 블로킹함