Thief of Wealth
article thumbnail

https://overreacted.io/ko/a-complete-guide-to-useeffect/

 

useEffect 완벽 가이드

이펙트는 데이터 흐름의 한 부분입니다.

overreacted.io

 

 

 

 

✅ useEffect로 componentDidMount 동작을 흉내내려면 어떻게 해야하는가?

=> 완전히 같지는 않지만 useEffect(fn, []) 형식으로 가능하다.

 

✅ 이펙트를 일으키는 의존성 배열에 함수를 명시해도 되는건가?

=> prop, state를 반드시 요구하지 않는 함수는 컴포넌트 바깥에 선언해서 호이스팅하고,

effect안에서만 사용되는 함수는 effect 내부에 선언하는 것이다.

만약 렌더 범위 안에있는 함수를 effect가 사용하고 있다면, 구현부를 useCallback으로 감싸면된다.

 

✅ 왜 가끔씩 데이터 fetch를 할 때 무한루프에 빠지는 것인가?

=> 이펙트 안에서 데이터 fetch 할 때 2번째 인자로 의존성 배열을 전달하지 않았을때 생길 수 있는 문제이다.

이게 없으면 effect가 매 렌더링마다 실행되어서, state를 변경하는 로직이 실행될 것이고, 다시 state를 변경했으므로 다시 렌더링을 하게 되어서 무한 루프가 돌게 된다.

 

물론 의존성 배열에 항상 바뀌는 값을 지정해두는 경우에도 무한 루프가 생길 수 있다.

그럴 때에는 하나씩 지워보면서 어디가 문제인지 체크할 수도 있지만, 사용하고 있는 의존 값을 지우는 것은 보통 잘못된 해결법이다.

보통 함수를 effect 밖으로 꺼내서 호이스팅하거나 useCallback을 사용해서 해결할 수 있당 (또는 useMemo)

 

  왜 가끔씩 이펙트 안에서 이전 state나 prop 값을 참조할까?

effect는 언제나 자신이 정의된 블록 안에서의 렌더링이 일어날 때마다 prop과 state를 지켜본다.

이전 값이 읽힌다는 것은 아마도 의존성 배열에 값을 지정하는 것을 깜빡했을 것이다.

 

 

 

 

모든 렌더링은 고유의 prop과 state가 있다.

state를 업데이트할 때마다, react는 컴포넌트를 호출합니다.

매 렌더 결과물은 고유의 counter 상태값을 "살펴봅니다"

그리고 state은 함수 안에 상수로 존재합니다.

 

즉, 각각의 렌더링마다 격리된 고유의 state이 있는 것입니다.

 

모든 렌더링은 고유의 이벤트 핸들러를 가진다.

위 state가 그랬듯이 함수도 코드 블록 내에서 상수로 존재하고, 상수인 state를 바라볼 수 있습니다.

즉, 특정 렌더링 시에 그 내부에서는 prop과 state는 영원히 같은 상태로 유지됩니다.

prop랑 state가 렌더링으로부터 분리가 되어있다면, 그것과 연관된 (이벤트 핸들러 등) 것들도 분리되어 있는 것입니다.

 

모든 렌더링은 고유의 이펙트를 가진다.

오 이번엔 effect까지 고유하게 가지고 있다고 한다.

이벤트 핸들러가 그 렌더링에 속한 고유의 state, prop값을 보듯이

effect도 똑같은 개념이 적용됩니다.

 

즉, 함수처럼 effect도 매 렌더링 마다 별도로 존재하게 됩니다. (매 렌더링마다 다른 함수라는 뜻)

 

또한, react는 effect를 함수를 기억해뒀다가 DOM의 변화를 처리하고 브라우저가 스크린에 그리고 난 뒤 실행합니다.

그리고 그 effect는 그 당시 렌더링할 때 있던 state와 prop를 볼 수 있습니다.

 

 

이러한 상황을 역할극으로 설명하자면 다음과 같습니다.

 

### 상황 1: 초기 렌더링

리액트: state초기값이 0이네 그 때의 UI를 내놔

 

컴포넌트: ㅇㅋ 여기 <div>...0...</div>

아, 그리고 다그렸으면 useEffect안에 있는 effect함수 실행시켜주라~

 

리액트: 그래~ UI업데이트 해줄게.

야 브라우저야 나 DOM에 좀 그려야겠다. 변경사항이 있어.

 

브라우저: ㅇㅋ 그려드림

 

리액트: 좋아 이제 effect를 실행시켜야겠군

(끝)

 

### 상황 2: 어떤 상호작용이 일어남

컴포넌트: 야야 리액트야 나 state가 1로 변경시켜주라

 

리액트: state가 1일때 UI 줘

 

컴포넌트: <div>...1...</div> 여기!

아 참, effect있다 알지?

 

리액트: 좋아 그려줄게,

브라우저야 알잘딱하자.

 

브라우저: 그렸습니다

 

리액트: 이제 effect를 실행해야겠군

(끝)

 

 

위 역할극을 통해서 모든 렌더링에서 고정된 state을 effect가 참조하는 것을 알 수 있고,

브라우저 렌더링이 끝나고 난뒤에 effect가 실행됨을 알 수 있습니다.

 

번외) 이렇듯 리액트는 기존 것들을 대부분 버리고 새롭게 다시 만들어서 사용한다. state든.. 함수든...

이것이 뭐가 좋은걸까? (위 참고 아티클에서 "엔트로피" 검색)

=> 이렇게 유지함으로써 컴포넌트들은 울타리를 쳐놓은 것처럼 추상화되어있어서, 같은 페이지의 그 어떤 코드들도 이 컴포넌트의 상태나 DOM을 망치지 않게 해준다.

물론 DOM을 지우고 다시 생성하는 것이 내부 상태가 파괴될 때마다 일어나서 비용이 있긴하다.

하지만 이런 "껏다켜기" 코딩 방법으로 디버깅이 훨씬 쉬워지고 복잡도를 줄일 수 있다.

위와 같은 코드를 살펴보자.

useEffect안의 함수는 브라우저에서 DOM 렌더링이 끝나고 실행되는데,

그 실행되어야 하는 함수가 DOM을 업데이틑 로직이다.

이러면 react의 흐름에 역행하는 것이고 동기화에 실패할 수 있다.

 

 

자 이제 effect가 어떻게 동작하는지 알았다.

그럼 이런 생각도 해볼 수 있을 것이다.

effect를 매번 렌더링 마다 실행하는 건 효율이 떨어지지 않을까?

 

당연하다.

 

그래서 우리는 React에게 이펙트를 비교하는 방법을 가르쳐주면 이 문제를 해결할 수 있다.

그게 바로 의존성 배열이다.

React는 effect를 업데이트 해야하는 경우를 의존성 배열로 판단하고 그것을 통해서 동기화 한다.

 

그렇기 때문에 React에게 의존성 배열로 거짓말을 하는 경우, 부작용이 있을 수 있다.

 

여기까지만 정리를 하고 나머지 케이스들을 직접 확인하자.

https://overreacted.io/ko/a-complete-guide-to-useeffect/

 

profile on loading

Loading...