React.js Effects와 clean-up 함수

강정우·2023년 1월 2일
0

react.js

목록 보기
16/45
post-thumbnail
post-custom-banner

Effect(Side Effects)

정의

  • 그동안 우리가 배웠던 것은 state나 이벤트등을 화면에 뿌려주는 것이었다.
    예를들어 JSX코드와 DOM을 평가하고 렌더링하고 state와 prop을 관리하는등 그렇다면 SideEffect란 무엇일까

  • 애플리케이션에서 일어나는 다른 모든 것을 뜻한다.
    예를 들면 http request를 보내는 것 또는 브라우저 저장소(로컬)에 무언가를 저장하는 것
    또한 코드에서 타이머나 간격을 설정하는 것 등

  • 데이터 fetching, subscriptions 혹은 수동적인 DOM 변경 등과 같이 컴포넌트의 렌더링과는 별개로 동작하는 것들을 가리킨다.

이러한 "side effect"는 주로 두 가지 훅, useEffectuseLayoutEffect를 통해 처리된다.
useEffect는 컴포넌트 렌더링이 완료된 후에 비동기적으로 실행되며,
useLayoutEffect는 렌더링 직후 동기적으로 실행되는 것이 특징이다.

예를 들어, "네트워크 요청" 같은 비동기 작업은 컴포넌트의 렌더링과 별도의 사이클에 있어야 하므로 이는 side effect로 볼 수 있다. 이러한 작업들은 useEffect 훅 안에서 처리하는 것이 적절하는 것이다.

문제는 이렇게 "별도의 사이클"에 있는 작업들을 적절히 처리하지 않으면 예상치 못한 문제를 야기할 수 있다.
예를 들어, 컴포넌트가 언마운트 된 후에도 비동기 작업이 완료되어 상태를 업데이트하려고 하면 메모리 누수 문제가 발생할 수 있다.
이런 문제를 방지하기 위해 useEffect에서는 cleanup 함수를 반환할 수 있다.
이 함수는 컴포넌트가 언마운트되거나, 의존성 배열에 있는 값이 변경될 때 호출되어 side effect를 정리한다.

문제점

  • 하지만 이런 작업들을 하려고 리액트를 쓰는 것은 아니다. 즉, 위와같은 일을은 컴포넌트와 다른,(컴포넌트 함수) 밖에서 일어나야하는 일이다.

  • 컴포넌트 함수내 state 변경점 식별 => 전체 컴포넌트 함수 재실행 => 함수의 결과값(새 JSX코드)확인 => 변경점 DOM을 이용하여 변경
    위와같은 상황으로 리액트가 동작하는데 예를들어
    http request응답으로 어떤 state를 변경하면 =>전체 컴포넌트 함수 재실행 => 함수 결과값 반환 => http request 요청 이런식으로 무한루프가 돌 수 있기 때문에 사이트이펙트는 직접적으로 컴포넌트 함수에 들어가면 안 된다.

  • 그래서 리액트 훅을 이용한다. {useEffect}

사용법

useEffect (() => { ... }, [ 의존성 ]);
  • 매개변수와 해당하는 함수를 첫번째 인수로 넣어줘야한다. 이는 모든 컴포넌트 평가 후 실행될 함수이다.

  • 지정된 의존성을 넣어줘야한다. 이는 배열이다. 그래서 이 의존성에 변경이 생길 때 마다 1번인수 함수가 다시 실행될 것이다.

  • 그렇다면 위 코드는 내가 지정한 의존성이 변경될 때만 실행되지 컴포넌트 함수가 변결될 때 실행되는 것이 아니기 때문에 안전하게 사용할 수 있다.

  • 자원을 많이 소비할 수 있는 이 코드는, 모든 컴포넌트가 다시 렌더링될 때마다 실행되지는 않고, 우리가 실행시키고 싶을 때(등록된 의존성에)만 실행이 된다.

  • 코드를 보면 위와같고 우선 컴포넌트 함수 바로 밑에 state가 나오고 다음 effect 훅이 나온다. effect 훅의 실행부에 여러가지 함수가 나올 수도 있다. 하지만 위를 보면 의존성이 한개도 주입이 안되어있는데 이는 컴포넌트함수가 렌더링될 때만 다시 실행되는 것이다.
  • 그래서 통상 effect 훅은 위와같이 사용된다. 의존성은 사이트 이펙트 함수에서 사용하는 것을 의존성으로 추가하면 된다 이때, 함수는 실행시키지 말고 pointer로 지정한다. 그래서 그 함수 자체가 실행되었을 때 effect 훅이 동작하기 때문이다.
    그런데 사실 setFormIsValid는 생략할 수 있다. 왜냐하면 state update 함수는 기본적으로 리액트에 의해 절대 변경되지 않도록 보장되기 때문이다.

즉, useEffect는 https request 뿐만 아니라
어떤 state나 props가 변결될 때 로직을 다시 실행하기 위해서도 사용이 된다.
따라서 매우 중요한 훅이고 무언가에 대한 응답으로 실행되는 코드를 다루는데 도움이 된다.

debouncing(그룹화) 와 clean-up 함수

  • 클릭을 할 때마다 지정한 로직을 돌아 결과값을 보여준다 이는 불필요한 네트워크 트래픽을 만든다. 따라서 우리는 사용자가 입력을 끝내면 그때 검증을하는 디바운스를 진행할 것이다.

  • useEffect의 첫번째 인수는 무엇인가를 반환할 수 있다. 단, 함수 자체여야한다. 즉, 이는 클린업함수라고도 불리는데 쉽게 말해 callback함수를 반환해야한다.
    useEffect가 다음번에 이 함수를 실행하기 전에.

    이 클린업함수는 useEffect 함수가 실행되기 전 클린업 함수가 실행된다.
    또는 컴포넌트가 재사용될 때마다 실행된다.
    단, 첫번째 사이드 이펙트함수가 실행된 전에는 실행 X

  • 위 사진을 보며 다시 설명하면 최초에

요약

  • 만약 우리가 이렇게만 적었다면 이 effect는 컴포넌트 함수가 실행될 때마다 계속 실행될 것이다.

  • 그리고 의존성을 한개도 추가안 했다면 위 effect는 최초 마운트 될 때, 최초 렌더링될 때만 사용된다.

  • 그리고 이와같이 의존성을 넣어주면 의존성 state가 변경될때마다 재실행된다.

  • 하지만 이 클린업 함수만큼은 강사와는 다른 현상을 보여주는데
    우선 최초 렌더링될 때 effect함수가 실행 => 의존성 변경에 따라 클린업함수 실행 => effect함수 실행

  • 하지만 e를 3번 입력한 결과는 나랑 조금 달랐다. 빨강이 네모가 최초 렌더링 될 때 파란색이 e를 3번 입력한 결과는
    렌더링 이펙트함수 실행 => 렌더링 클린업함수 => 렌더링 이팩트실행 => 렌더링 유효성 그니까
    렌더링될 때 실행되지 않는다던 클린업함수가 실행되어버리는 것이다. 그래서 존나 헷갈림
    이건 추후 업데이트 하겠다.

그니까 그냥 return부터 시작된다라고 생각해야겠다.

주의사항

  • 특정 속성을 종속성으로 전달하는 것이 좋다.
    사실 아래와 같이 써도 작동은 된다.
useEffect(() => {
  // code that only uses someProperty ...
}, [someObject]);

하지만 위는 좋은 예시가 아니다. 왜일까?
왜냐하면 effect 함수는 someObject 가 변경될 때마다 재실행되기 때문이다.
즉, 너무 빈번하게 실행되기에 과부하를 줄 수 있다.
따라서 아래와 같이 사용하면 가장 좋다.

useEffect(() => {
  // code that only uses someProperty ...
}, [someObject.someProperty]);
profile
智(지)! 德(덕)! 體(체)!
post-custom-banner

0개의 댓글