[React] useEffect

pyozz·2024년 1월 15일
post-thumbnail

Side Effect(부수 효과)란?

실행되어야 하는 작업이지만 현 컴포넌트 렌더링 과정에 직접적이고 즉각적인 영향을 미치지 않는 것

예를 들어, 여러 나라의 이름을 요소로하는 배열이 있고 사용자의 위치와 가까운 순서대로 이 배열을 정렬한다고 하면 사용자의 위치를 전달하고 거리를 구하는 로직은 side effect라고 할 수 있다. 왜냐하면 그 로직이 앱에 필요하기는 하지만 컴포넌트의 주된 목적인 렌더링이 가능한 jsx 코드를 반환하는 것과 같은 직접적인 연관성이 없기 때문이다.

추가로 클릭에 대한 이벤트 리스너 설정이나 useState 등이 있다면 이것은 화면에 보여지는 것이기 때문에 side effect라고 할 수 없다.

Side Effect의 잠재적 문제: 무한 루프

위 사용자 위치를 기준으로 정렬된 배열 데이터를 화면에 나타내기 위해 useState로 관리하게 된다면 다음과 같은 현상이 발생한다.

  1. 처음 컴포넌트가 실행되어서 사용자의 위치 정보를 기반으로 배열을 정렬하고 state에 저장한다.
  2. state의 변경으로 인해 컴포넌트가 재실행되어서 배열을 정렬하고 state에 저장되는 코드도 다시 실행된다.
  3. state의 변경으로 인해 컴포넌트가 또 재실행되어서 배열을 정렬하고 state에 저장되는 코드도 또 다시 실행된다.
  4. 반복...

useEffect 훅을 사용하는 Side Effect

위 문제를 해결하기 위해 useEffect 훅을 사용할 수 있다.

useEffect(이펙트 함수, 의존성 배열);
  • 이펙트 함수는 컴포넌트 함수가 모두 실행 완료된 이후(jsx까지 반환된 후)에 실행된다.
    이펙트 함수에 상태를 업데이트하는 함수가 있어서 컴포넌트 재실행으로 인해 이펙트 함수도 재실행될 것 같지만 명시된 의존성 배열을 살펴보고 의존성 배열의 요소가 변했을 때만 이펙트 함수를 재실행 시킨다.
  • 의존성 배열 안에 있는 변수 중에 하나라도 값이 변경되면 이펙트 함수가 실행된다.
function App() {
  	const [places, setPlaces] = useState([]);
  
	useEffect(() => {
    	// 1. 사용자 정보를 취득하고 이를 기준으로 배열 데이터를 정렬
      	sortedPlaces = 
        ...
      
		// 2. 상태 업데이트      
      	setPlaces(sortedPlaces)
    }, [])
}

모든 사이드 이펙트에 useEffect를 사용하는 것은 아니다. 이펙트 함수로는 컴포넌트가 실행된 이후, 렌더링 이후에 실행되어도 되는 작업 로직들을 작성해야한다.

Effect Dependencies(의존성)

이펙트 함수가 실행되는 때를 정리해보면

  • 의존성 배열 : 처음 마운트 될 때와 의존성 배열 값 중 하나라도 변할 때
  • 의존성 배열 생략 : 처음 마운트 될 때와 업데이트 될 때마다
  • 빈 배열 : 처음 마운트 될 때와 언마운트 될 때

useEffect의 cleanup 함수

useEffect의 이펙트 함수가 반환하는 함수로, 컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 수행할 작업이 있는 경우 사용한다.

함수 의존성의 문제점

함수도 객체 값이기 때문에 매번 실행될 때마다 새롭게 정의된다. 따라서, 함수를 의존성 배열에 넣으면 컴포넌트가 실행될 때마다 함수 의존성이 변한 것으로 인식해 이펙트 함수를 실행시키게 되고 만약 거기에 상태를 업데이트하는 함수가 있다면 무한 루프에 빠질 수가 있다.

이를 위해 함수가 매번 재정의 되지 않도록 하는 useCallback 훅을 사용할 수 있다. useEffect와 마찬가지로 의존성 배열에 있는 값이 변했을 때만 해당 함수를 정의하게끔한다.

0개의 댓글