본문 바로가기

개발/Web

[React] useEffect

useEffect란?

"useEffect"는 개발자가 선언적인 방식으로 함수형 컴포넌트에 생명주기 메서드를 추가할 수 있게 해주는 React Hook입니다. 클래스 기반 컴포넌트의 필요성과 "componentDidMount", "componentDidUpdate", "componentWillUnmount"와 같은 수명 주기 메서드의 사용을 대체합니다. 개발자는 useEffect를 사용하여 컴포넌트 부작용을 관리하고 데이터 가져오기, DOM 조작, 이벤트 구독과 같은 작업을 수행할 수 있습니다.

 

장점

함수형 컴포넌트에 수명 주기 메서드 추가 간소화

React에 useEffect가 도입되기 전에는 함수형 컴포넌트에는 componentDidMount, componentDidUpdate, componentWillUnmount와 같은 수명 주기 메서드에 접근할 수 없었습니다. 이는 개발자가 컴포넌트 상태와 부작용을 관리하기 위해 클래스 기반 컴포넌트를 사용해야 한다는 것을 의미했습니다. 이제 사용효과가 도입되면서 개발자는 함수형 컴포넌트를 사용하면서도 선언적 방식으로 수명 주기 메서드를 추가할 수 있습니다.

다음은 useEffect를 사용하여 componentDidMount 수명 주기 메서드를 모방하는 방법의 예시입니다:

이 예시에서는 컴포넌트가 마운트될 때 API에서 데이터를 가져오기 위해 useEffect를 사용하고 있습니다. 빈 의존성 배열 []은 componentDidMount와 마찬가지로 이펙트가 한 번만 실행되도록 합니다.

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

function Example() {
  const [data, setData] = useState(null);

  useEffect(() => {
    async function fetchData() {
      const response = await fetch('https://api.example.com/data');
      const json = await response.json();
      setData(json);
    }
    fetchData();
  }, []);

  if (!data) return <div>Loading...</div>;

  return (
    <ul>
      {data.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

업데이트 타이밍 및 빈도 제어

개발자는 의존성 배열에 의존성을 지정하여 사용효과 훅이 언제, 얼마나 자주 실행되는지 제어할 수 있습니다. 이를 통해 불필요한 렌더링을 줄이고 효율성을 개선하여 React 애플리케이션의 성능을 최적화할 수 있습니다.


다음은 소품이 변경될 때 컴포넌트를 업데이트하기 위해 useEffect를 사용하는 방법의 예시입니다:

이 예시에서는 useEffect를 사용하여 소품이 변경될 때 상태를 업데이트하고 있습니다. 의존성 배열에 소품을 전달함으로써, 소품이 변경될 때마다 사용효과가 다시 실행되도록 지시하고 있습니다.

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

function Example({ prop }) {
  const [state, setState] = useState(null);

  useEffect(() => {
    setState(prop);
  }, [prop]);

  return <div>{state}</div>;
}

단점

기존 수명 주기 방법보다 추론하기 어려울 수 있음
사용 효과는 함수형 컴포넌트에 수명 주기 메서드를 추가하는 프로세스를 단순화하지만, 기존의 수명 주기 메서드보다 이해하고 추론하기가 더 어려울 수 있습니다. 사용 효과는 다양한 방식으로 사용될 수 있기 때문에 언제 어디서 사용해야 하는지 결정하기 어려워 잠재적인 버그와 오류가 발생할 수 있습니다.

예를 들어 API에서 데이터를 가져와서 표시해야 하는 컴포넌트가 있다고 가정해 봅시다. 컴포넌트가 마운트될 때 데이터를 가져오고 컴포넌트 상태를 업데이트하기 위해 useEffect를 사용할 수 있습니다:

이 예제에서는 useEffect를 사용하여 API에서 데이터를 가져오고 컴포넌트가 마운트될 때 컴포넌트 상태를 업데이트하고 있습니다. 하지만 이 코드에는 잠재적인 문제가 있습니다. API 엔드포인트가 변경되면 컴포넌트가 새 데이터를 반영하도록 자동으로 업데이트되지 않습니다. 새로운 API 엔드포인트를 포함하도록 사용효과 의존성 배열을 수동으로 업데이트해야 합니다.


이 예시는 componentDidMount와 같은 기존의 라이프사이클 메서드에 비해 useEffect의 동작을 추론하는 것이 얼마나 어려운지 보여줍니다. 개발자는 잠재적인 버그와 문제를 방지하기 위해 사용Effect를 언제, 어떻게 사용할지 신중하게 고려해야 합니다.

이 예시에서는 컴포넌트가 마운트될 때 API에서 데이터를 가져오는 데 useEffect 훅이 사용됩니다. 의존성 배열이 비어 있으므로 컴포넌트가 마운트될 때 이펙트가 한 번만 실행됩니다. 가져온 데이터는 "useState" 훅을 사용하여 상태에 저장되며, 컴포넌트는 데이터가 로드되면 항목 목록을 렌더링합니다.

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

function Example() {
  const [data, setData] = useState([]);

  useEffect(() => {
    async function fetchData() {
      const response = await fetch('https://api.example.com/data');
      const json = await response.json();
      setData(json);
    }
    fetchData();
  }, []);

  return (
    <ul>
      {data.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

useEffect 사용 이유

개발자가 프로젝트에서 사용효과를 사용하는 데에는 몇 가지 이유가 있습니다. 한 가지 이유는 함수형 컴포넌트에 라이프사이클 메서드를 추가하는 프로세스를 간소화하여 코드를 더 읽기 쉽고 유지 관리하기 쉽도록 만들기 때문입니다.

또 다른 이유는 사용효과가 불필요한 렌더링을 줄이고 업데이트를 최적화하여 React 애플리케이션의 성능을 향상시킬 수 있기 때문입니다. 그 결과 로드 시간이 빨라지고 사용자 경험이 향상될 수 있습니다.

useEffect 사용 예시다음은 컴포넌트가 마운트될 때 API에서 데이터를 가져오는 데 useEffect를 사용하는 예시입니다:

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

function Example() {
  const [data, setData] = useState(null);

  useEffect(() => {
    async function fetchData() {
      const response = await fetch('https://api.example.com/data');
      const json = await response.json();
      setData(json);
    }
    fetchData();
  }, []);

  if (!data) return <div>Loading...</div>;

  return (
    <ul>
      {data.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

Q&A

질문: 이펙트 후 정리는 어떻게 하나요?
A: 다음과 같은 경우에 호출될 이펙트에서 함수를 반환할 수 있습니다.

이 예제에서 이펙트는 매초마다 '틱'을 기록하는 간격을 설정합니다. 이 이펙트는 컴포넌트가 마운트 해제되거나 이펙트가 다른 종속성으로 다시 실행될 때 간격을 지우는 함수도 반환합니다. 이는 메모리 누수 및 기타 문제를 방지하는 데 중요합니다.

function MyComponent() {
  useEffect(() => {
    const intervalId = setInterval(() => {
      console.log('tick');
    }, 1000);

    return () => {
      clearInterval(intervalId);
    };
  }, []);

  return <div>Component</div>;
}

 

 

질문: 단일 컴포넌트에서 여러 개의 useEffect 후크를 사용할 수 있나요?
A: 예, 단일 컴포넌트에서 여러 개의 useEffect 후크를 사용할 수 있습니다. 각 효과는 다른 효과와 독립적으로 실행됩니다.