본문 바로가기
Frontend/React

React Side Effects와 useEffect

by Forsaken Developer 2023. 1. 24.
728x90
728x90

React Side Effects와 useEffect

Side Effects란

리액트 앱의 컴포넌트의 주요 역할은 UI를 렌더링하는 것이다.

state나 event, 그 모든 것의 주요 역할은 화면에 무언가를 가져오는 것이었다.

예를 들어 버튼이 클릭 되거나 어떤 텍스트가 입력되는 특정 이벤트에 따라 따라서 화면에 보이는 것은 변경될 수 있고 이것이 리액트가 애플리케이션에서 주로 하는 일이다.

사이드이펙트는 애플리케이션에서 일어나는 다른 모든 것을 뜻한다.

예를 들면 http request, local storage에 저장, timer설정 등 이것 들은 모두 애플리케이션에서 고려해야 하는작업이지만 화면에 무언가를 가져오는 것과는 관련이 없다.

그것은 리액트가 신경써야할 것이 아니고 그런 일을 하려고 리액트가 있는 게 아니다.

따라서 이것 들은 일반적인 컴포넌트 함수의 밖에서 일어나야 하는 일이다.

예를 들어 http request 컴포넌트 함수의 내부에서 호출하면 state가 변경될 때마다 이 함수가 다시 실행되고 request를 다시 보내게 되므로 많은 request 요청이 발생된다.

또한 http request에 대한 응답으로 어떤 state를 변경한다면 함수가 다시 실행될 때마다 request를 보내고 request에 대한 응답으로 state를 변경하게 되는 무한루프에 빠질 수 있다.

따라서 그런 사이드이펙트는 직접적으로 컴포넌트 함수에 들어가서는 안된다.

UseEffect

그러므로 사이드이펙트를 처리할 때는 useEffect 훅을 사용해야한다.

useEffect hook은 두 개의 매개변수와 같이 호출된다.

첫 번째 인수는 지정된 의존성이 변경된 경우 실행되어야 하는 함수이며 두 번째 인수는 지정된 의존성으로 구성된 배열이다.

의존성이 변경될 때마다 첫 매개변수의 함수가 다시 실행되기때문에 어떤 사이드이펙트 코드라도 넣을 수 있다.

컴포넌트가 다시 렌더링될 때는 실행되지 않고 의존성이 변경된 경우에만 실행된다.

useEffect(() => {
    console.log("실행");
  }, [state1, state2]);

기본적인 사용 방법이다. state1 또는 state2가 변경될 때마다 첫 번째 매개변수인 함수가 실행된다.

useEffect 함수에서 사용하는 모든 것을 종속성으로 추가해야 하기 때문에 사용하는 모든 상태 변수와 함수를 포함한다. 그렇지만 몇 가지 예외가 있다.

  • 상태 업데이트 기능을 추가할 필요가 없다. ( setState() ) React는 해당 함수가 절대 변경되지 않도록 보장하므로 종속성으로 추가할 필요가 없다.
  • 내장 API 또는 함수를 추가할 필요가 없다. ( fetch(),  localStorage  등) 이러한 브라우저 API는 React 구성 요소 렌더링 주기와 관련이 없으며 변경되지 않는다.
  • 변수나 함수를 추가할 필요가 없다. (let var1; ,const fun1 = () ⇒ {} )이러한 함수 또는 변수도 함수 내부에서 생성되지 않으므로 변경해도 구성 요소에 영향을 주지 않는다.

그렇기 때문에 컴포넌트 함수에 정의된 변수나 상태, 컴포넌트 함수에 정의된 props 또는 함수를 종속성으로 추가해야한다.

useEffect(() => {
    console.log("실행");

    return () => {
      console.log("Cleanup");
    };
  }, [state1, state2]);

첫 번째 인수로 전달하는 함수는 함수를 반환할 수 있는데 이를 클린업 함수라고 한다.

클린업 함수는 useEffect가 다음 번에 이 함수를 실행하기 전에, 컴포넌트가 DOM에서 마운트 해제될 때마다 실행된다.

즉 클린업 함수는 모든 새로운 사이드이펙트 함수가 실행되기 전에, 그리고 컴포넌트가 제거되기 전에 실행된다.

또한 첫 번째 사이드이펙트 함수가 실행되기 전에는 실행되지 않는다.

useEffect(() => {
    const identifier = setTimeout(() => {
      setFormIsValid(emailIsValid && passwordIsValid);
    }, 1000);

    return () => {
      clearTimeout(identifier);
    };
  }, [emailIsValid, passwordIsValid]);

클린업 함수를 언제 어떻게 써야 하는지 보여주는 대표적인 예이다. 로그인 폼에서 이메일과 비밀번호를 입력할 때마다 유효성을 확인하는 경우이다.

키가 입력될 때마다 이런 일을 하고 싶진 않을 것이다.

이 간단한 작업은 괜찮을지 몰라도 사용자 이름이 이미 사용 중인지 확인하기 위해서 http request를 키가 입력될 때마다 확인한다면 상당히 불필요한 네트워크 트래픽을 만들 것이다.

이에 대한 해결책으로 일정량의 키 입력을 수집하거나 또는 키 입력 후 일정 시간 동안 일시 중지되는 것을 기다리는 방법이 있다.

사용자가 적극적으로 타이핑하는 동안에는 유효한 이메일 주소인지 확인하지 않고 예를 들어 1초 이상 멈춘다면 그때 유효성을 확인한다.

이것을 debouncing 이라고 하는데 사용자 입력을 debounce(그룹화) 하는 기술이다.

728x90
반응형

댓글