useEffect

SebellKO·2023년 10월 12일

React

목록 보기
10/15
post-thumbnail

side effect

오늘은 React에서 제공하는 useEffect 훅에 대해서 알아보자.

useEffect를 알아보기 전에 알아야할 한가지 개념이 있다. 바로 side effect이다.

side effect란 프로그램 또는 함수의 실행과는 독립적으로 발생하며, 주로 외부 환경에 영향을 미치는 것을 말한다.

예를 들자면 외부 API 호출이나 DOM에 접근하여 변경 / 조작하는 작업, setTimeout / setInterval을 사용해 타이머를 설정할때 발생한다.

이런 side effect의 처리를 도와주는 기능이 useEffect 훅이다.

side effect를 왜 useEffect로 처리해야하는지 예제를 통해 알아보자.


useEffect()

useEffect는 생명주기와 관련된 작업을 수행하거나 다른 데이터에 의존하는 작업을 처리하는 데 사용됩니다.

기본형은 useEffect(() => {}, []) 이며 첫번째 인자로 컴포넌트 렌더링시 실행시킬 함수를 넘겨주고, 두번째 인자로 의존성 배열을 넘겨줍니다.

setInterval을 사용해 side effect가 발생하는 코드를 먼저 확인해보자.

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

function TimerComponent() {
  const [time, setTime] = useState(0);
  const [user, setUser] = useState({});
  
  const userData = fetch('http://example.com/user')
  	.then(response  => response.json())
  	.then(result => setUser(result))
  	.catch(error => console.log(error));

  const timerId = setTimeout(() => {
    setTime(time + 1);
  }, 500);

  return <div>Time: {time}</div>;
}

export default TimerComponent;

위 코드를 보면 time, user state가 있고 각각 timerId, userData를 통해 상태가 변경되고 있다. 우리는 state가 변경되면 컴포넌트가 다시 렌더링 되는것을 알고있다.

이 경우 만약 userData를 가져와 setUser(result) 하는 과정보다 setTimeout 내부 setTime(time + 1)이 계속해서 더 빨리 실행된다면 렌더링은 계속해서 일어날 것이고 userDatatimerId를 제거하지 않는 이상 데이터를 가져올 수 없을것이다.

위 같은 문제를 해결하기 위해서 useEffect를 사용한다.

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

function TimerComponent() {
  const [time, setTime] = useState(0);
  const [user, setUser] = useState({});
  
  useEffect(() => {
      const userData = fetch('http://example.com/user')
  	.then(response  => response.json())
  	.then(result => setUser(result))
  	.catch(error => console.log(error));
   ,[user]});

    
  useEffect(() => {
  	const timerId = setTimeout(() => {
      setTime(time + 1);
    }, 500);
  },[time])
    
  return <div>Time: {time}</div>;
}

export default TimerComponent;

위 코드와 같이 useEffect 의 첫번째 인수로 실행할 함수를 넘겨주고 두번째 인수로 종속성 배열을 넘겨준다. 위 두개의 useEffect 훅 처럼 각 user, time을 넘겨주면 첫번째 훅은 user의 상태가 변경될 때에만 실행이 되며 두번째 훅도 마찬가지로 time의 상태가 변경 될때만 실행된다.

기능적인 면에서 봤을때 userData를 가져오는 구문은 아래와 같이 작성하는것이 옳다.

useEffect(() => {
      const userData = fetch('http://example.com/user')
  	.then(response  => response.json())
  	.then(result => setUser(result))
  	.catch(error => console.log(error));
   ,[]});

바로 종속성 배열에 아무값도 넣지 않는것이다.

이렇게 할경우 useEffect 는 컴포넌트가 처음 렌더링 될때만 실행된다.


clean up

clean up 함수는 useEffect 내부에서 반환되는 함수를 말한다.

주로 useEffect에 의해 설정된 side effect를 해제하거나 정리하는데 사용되며, 컴포넌트가 언마운트 되거나 useEffect의 의존성 배열이 변경될 때 이전 side effect를 정리하는데 사용된다.

위에서 사용했던 코드를 가져와 살펴보자.

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

function TimerComponent() {
  const [time, setTime] = useState(0);

  useEffect(() => {
    const timerId = setTimeout(() => {
      setTime(time + 1);
    }, 1000);
    
    return () => {
      clearTimeout(timerId);
    };
  }, [time]);

  return <div>Time: {time}</div>;
}

export default TimerComponent;

useEffect 내부 clearTimeout(timerId)를 실행시켜 컴포넌트가 언마운트 될때 설정해둔 타이머를 제거시켰다.

위와 같이 clean up을 해주지 않을경우 해당 컴포넌트가 언마운트 되어도 백그라운드에서 계속해서 time + 1 타이머가 계속해서 동작하게 되고 메모리 누수와 같은 문제가 발생할 수 있다.

다음은 useReducer를 만나보자.

0개의 댓글