본문 바로가기
TIL

useEffect 란?

by 은지:) 2022. 8. 8.
728x90
반응형

 

 

 

 

 

 

React에서 side Effect의 올바른 발생 시점

 

 

 

 

const App = () => {
    const doSideEffect = () => // do some side effect }; // 함수 정의
    doSIdeEffect() // 함수 호출
    
    return <h1> hello world </h1>; //jsx 리턴
}

 

👆 위 코드는 리턴문 위에서 하고 싶은 동작을 실행 시킨다

 

 

 

 

 

 

문제점

 

 

1. sideEffect가 렌더링을 blocking 함

 

코드는 위에서 아래로 읽음, doSideEffect의 동작이 끝날 때까지 jsx를 return 하는 코드로 넘어가지 않음

만약 여기서 doSideEffect가 시간이 오래 걸리는 sideEffect 라면 함수 컴퍼넌트가 jsx를 리턴하기 전까지 브라우저 상의 UI가 렌더링 되기까지 오랜시간이 걸린다 -> 사용자가 UI가 업데이트 되는 것을 보기까지 오랜 시간이 소요됨

 

2. 매 렌더링 마다 sideEffect가 수행됨

 

예를 들어 인스타 그램 피드를 보여주기 위해서 인스타 정보를 가져오는 사이드 이펙트가 필요함

이때 좋아요 하트 버튼을 누른다 했을 때 하트를 누를 때마다 UI 변화가 필요하다면, 하트를 누를때마다 리렌더링을 발생 시켜야 함

리액트에서 함수 컴포넌트 리렌더링은 함수 컴포넌트를 다시 호출하는 방식으로 실행됨

즉, 매 렌더링마다 함수 컴포넌트가 호출되는 것

 

data fetching 등 특정한 상황에서만 필요한 사이드 이펙트가 매 렌더링마다 무조건 발생하게 된다면 비효율적

 

 

 

올바른 발생 시점

 

 

1. 렌더링을 blocking 하지 않기 위해 렌더링이 모두 완료되고 난 후 실행할 수 있어야 한다

2. 매 렌더링마다 실행되는 것이 아니라 원할 때만 조건부로 실행할 수 있어야 한다.

 

-> 다행히 리액트에선 useEffect 가 있어서 편하게 코드를 짤 수 있다

 

 

 

 

 

 

 

 

 

 

 

❗️ 그렇다면 useEffect 란?

 

 

렌더링이 모두 완료된 후 실행할 수 있고

원할 때만 조건부로 실행할 수 있다

 

 

 

 

 

 

 

 

 

 

useEffect

 

 

 

하지만 위 코드👆는 side Effect가 렌더링을 blocking 한다는 점만 해결함

 

 

 

 

 

 

 

👇 버튼을 누르거나 텍스트를 입력할 때마다 함수들이 같이 발동함 

 

 

 

 

 

👇 계속 쌓이는 side effect with useEffect, 비효율적이다

 

 

 

 

 

 

이를 해결하기 위해서 의존성 배열을 넣어주는데

 

 

👆 이렇게 의존성 배열을 같이 넣어주면 원하는 시점에 사이드 이펙트를 발생시킬 수 있다

 

 

 

 

 

 

위 콘솔창을 보면 버튼을 누를 때마다 text change는 콘솔에 안 찍히는 것을 확인할 수 있다

마찬가지로 text 를 입력할 때마다 count change도 찍히지 않는다

 

배열에 담긴 값에 하나라도 변화가 있다면 실행되는 것!

 

 

 

when? 은 [count, text] 두 인자를 넣은 useEffect로

둘 중 하나라도 변했기에 이펙트를 계속 실행된 것이다

 

마지막에 구분을 위해 넣어둔 console.log '------'은 따로 의존성 배열을 주지 않았기 때문에

계속 찍히는 것을 확인할 수 있다

 

 

 

❗️ 찻반쩨 렌더링에서만 콜백함수를 호출하고 두번째 렌더링에서부턴 호출하지 않게 하려면?

-> 의존성 배열에 [] 빈값을 넣어주면 됨

하나라도 변화가 있다면 실행되는 useEffect 의존성 배열에 애초에 비교할 값이 없기 때문!

 

 

 

 

 

 

effect - rendering cycle

 

1. 컴포넌트가 렌더링 된다 ( 브라우저에 컴포넌트가 보였다는 의미로 'mount'라 표현)

2. useEffect 첫번째 인자로 넘겨준 콜백 함수가 호출된다 (side Effect)

3. 컴포넌트 state 또는 props가 변경되었을 경우 리렌더링이 발생 (update)

4. useEffect는 두번째 인자에 들어있는 의존성 배열을 확인

5. state 또는 props 가 변경된다면 3-4의 과정을 반복

6. 컴포넌트가 더 이상 필요없어지면 화면에서 사라진다 ( 브라우저 화면에서 사라졌다는 의미로 'unmount' 라고 표현

 

 

 

 

 

 

 

 

 

 

clean up

 

 

 

 

 

그냥 들어가면 콘솔에 interval 1,2,3,4 숫자 세는 함수를 넣음

그리고 다른 페이지인 other 에 갈 수 있도록 링크를 걸어주었다

 

 

 

 

 

그리고 콘솔창을 확인했을 때, 다른 창으로 넘어가도 계속 실행되고 있는 interval

 

이런 것들은 지속적으로 구독을 하면서 남아 있는 이펙트이다

이는 other 창에선 불필요한 상태임으로 비효율적임!

 

 

 

바로 이럴 때

우리가 필요할 때만 사용하고 정리해주는 cleanup 이라는 개념이 있다

 

 

 

 

 

 

 

다시 코드를 정비해서

 

 

 

effect를 콘솔에 출력하는 useEffect

button 을 누를 때마다 콘솔에 button clicked 를 출력하는 useEffect

렌더링이 돌 때마다 찍히는 render 가 있다

 

 

 

 

콘솔에 찍어보면👇

 

 

 

 

일단 처음엔 모두 다 렌더링이 된다

다음 print console 버튼을 5번 눌렀더니 button clicked 이 5번 찍혔고

다음 up 버튼을 눌러 리렌더링을 한 다음

다시 button clicked 한번 눌렀더니 button clicked가 2번 찍혔다

 

 

 

후에 up 버튼을 30번 누른 후

button clicked 을 한번 눌렀더니

총 31번의 button clicked 이 생겼다 

 

 

이벤트 리스너가 중첩되고 있는 것...!

이때 다음 이펙트가 발생하기 전에

기존 부착해둔 eventListener 를 제거하고

새롭게 effect를 발생시키면 된다

 

 

 

클린업은 우리가 동작하고 싶은 것을 함수 형태로 만들어서 return 하면 된다

 

 

button useEffect 안에 cleanUp 함수를 넣어주었다

확인해보기 위해 clean up 콘솔을 넣고

 

다음 이펙트가 발생하기 전에 기존 이펙트를 제거하는 remove.EventListener 를 넣었다

 

 

 

 

👇결과

 

 

 

렌더링이 되어 나오므로 콘솔에 한번씩 찍히고

다음 Print console 버튼을 10번 누르고 리렌더링하러 up을 눌렀다

그랬더니 clean up 이라는 콘솔이 마지막에 따라 찍혔다

3번 더 누르고 button clicked을 다시 눌러봤을 때

이벤트가 중첩이 되지 않아 아까와 다르게 한번만 찍힌 것을 확인할 수 있다

 

 

이렇게 cleanUp 함수를 적용해주면 다음 이펙트가 실행되기 전에 클린업 함수를 호출해준다

 

그리고 useEffect는 다음 이펙트가 발생하기 전뿐만 아니라

컴포넌트가 언마운트 될 때에도 마찬가지로 클린업 함수를 호출한다

 

 

 

 

 

 

컴포넌트가 언마운트 될 때 클린업 함수 호출

 

 

👆 setInterval을 적용한 useEffect

 

useEffect 밖에 있는 console.log("render")가 먼저 콘솔에 찍히고

순서대로 effect, interval 이 찍힌다

 

그리고 이걸

 

 

 

 👇요렇게 바꾸어주면

 

 

 

 

 

 

 

 

 

이렇게 other 라는 페이지에 가면

clean up 이라는 콘솔이 뜨며 interval이 멈춘다

 

 

 

 

 

 

 

 

 

 

 

마지막 정리

 

react 에서 side Effect를 발생시킬 때 충족 시켜야 하는 조건

1. 렌더링 이후에 발생 시킬 것

2. 매 렌더링 이후가 아니라 조건부로 원하는 순간에만 실행할 수 있을 것

 

-> React 에서는 이를 충족시킬 수 있는 useEffect라는 Hook을 제공해준다

-> 하지만 일부 SideEffect 는 발생시킨 후 다시 cleanUp 하는 과정이 필요할 수 있다

-> useEffect에 인자로 전달한 콜백 함수에서 함수를 return 하면 다음 effect가 실행되기 전과, 컴포넌트가 unmount 될 때

return 된 함수를 호출해주며 이를 통해 기존의 side effect 를 cleanup 할 수 있다

 

 

 

 

 

 

 

728x90
반응형

'TIL' 카테고리의 다른 글

Monster 과제 (react, map함수, 컴포넌트)  (0) 2022.08.15
상수데이터란?  (0) 2022.08.12
SideEffect 란?  (0) 2022.08.08
인스타 main창 클론 react편  (2) 2022.08.07
인스타 login창 클론 react편  (0) 2022.08.06

댓글