들어가기 전에

이 글은 useEffect API에 대해 어느정도 익숙한 독자를 위한 글입니다.
그리고 오역과 의역이 많을 수 있으니 이상하다 싶은 부분은 원래 문서를 참고해주시기 바랍니다.

A Complete Guide to useEffect - Dan Abramov 에서 정보를 얻어 번역하였습니다.
I got information from here and translated it.


본문

우리는 Hooks를 사용하여 컴포넌트들을 작성하고 매우 만족합니다! 왜냐면 매우 편리하기 때문이죠 !!

하지만, useEffect를 사용하면서 뭔가 조각들이 서로 잘 어울리지 않고 놓치고 있는 느낌이 들지 않나요 ? 예를 들어 라이프 사이클과 관련된 그런것들 말이에요.
아래 질문들을 자신에게 한번 물어보세요.

  • componentDidMountuseEffect를 사용하여 대체할 수 있나요?
  • useEffect 안에서 데이터를 어떻게 올바르게 fetch 할 수 있나요? 그리고 [] 이건 뭔가요?
  • 함수를 effect에 의존되게 작성해야 할까요?
  • 왜 가끔가다 refetching loop에 걸리는 것 일 까요?
  • 내 effect에서 왜 오래된 state나 props 값 이 나올까요?

이 글의 원문 작성자가 Hooks를 처음 사용하기 시작하면서 위 질문들이 그를 계속 혼란스럽게 만들었다고 합니다. 그리고 그 이후로 원작자가 위 질문에 대해 깨달은 순간을 공유하려고 합니다.


1. componentDidMountuseEffect를 사용하여 대체할 수 있나요?

useEffect(fn, []) 를 대체하여 사용할 수는 있지만, 그렇다고componentDidMountuseEffect가 완전히 똑같은 것은 아닙니다. useEffectcomponentDidMount와 달리 props와 state를 capture 할 수 있고, 그 안에 있는 callback에서는 초기 props값과 초기 state값을 볼 수 있습니다.

예를 들어, 만약 당신이 맨 마지막에 들어오는 값을 필요로 할 때, 당신은 ref 를 사용하여 코드를 작성할 수 있습니다.

하지만, 그럴 필요 없습니다. 더 간단하게 코드를 구조화 할 수 있는 방법이 있기 때문이죠. 여기서 이 문제를 해결하기 위해 당신이 꼭 명심해야 할 것은effect의 기본적인 모델은 componentDidMount,그 이외의 lifecycle의 기본적인 모델과 다르다는 것 입니다. 결론적으로 그 둘 사이의 정확히 일치하는 공통점을 찾으려고 하는 것은 당신이 혼란스러워 할 수 있는 일이 될 수 있다는 이야기입니다.
따라서, 생산적인 코드를 작성하려면, "think in effects"하세요.

effects의 기본 모델은 Lifecycle 이벤트에 대응하는 것보다 동기화를 구현하는데 가까운 모델이라고 할 수 있습니다.

2. useEffect 안에서 데이터를 어떻게 올바르게 fetch 할 수 있나요? 그리고 [] 이건 뭔가요?

이 글useEffect를 사용하여 데이터를 fetch 하는데 좋은 발판이 될 수 있을 것입니다. 이 글을 확실히 끝까지 읽으세요! 제가 지금 번역하고 있는 이 글보다 길지 않습니다.

[] 이 빈 대괄호의 뜻은 effectReact 앱 안에서 데이터 흐름을 구성하고 있는 어떤 값을 아무것도 사용하고 있지 않다는 의미입니다. 그래서 궁금하면 그냥 한 번 써봐도 괜찮습니다. 하지만 이것은 흔하게 버그를 일으킬 수 있는 코드 이기도 합니다.

여러분은 다른 전략(? strategies)를 공부해봐도 좋을 것 같습니다. (주로 useReduceruseCallback)
that can remove the need for a dependency instead of incorrectly omitting it. (한국어로 어떤 느낌으로 번역해야 할 지 모르겠습니다..)

3. 함수를 effect에 의존되게 작성해야 할까요?

추천하는 방법으로는, props나 state가 필요하지 않는 함수들은 컴포넌트 외부에서 호이스팅 하고, effect 안에서는 그 effect 안에서만 사용되는 것들로만 구성해야 합니다.

만약, 여러분이 만든 effectrender 범위 안에서 계속 사용된다면, effect들이 정의된 곳에서 useCallback으로 감싼 뒤, 계속 진행하세요.

4. 왜 가끔가다 refetching loop에 걸리는 것 일 까요?

이것은 두번째 인자를 넣지 않고 effect를 사용하여 데이터를 fetch 할 때 일어날 수 있는 일 입니다. 두번째 인자가 없다면, render가 모두 마친 뒤에 effect가 실행되며, state를 설정하면 다시 effect는 트리거 될 것 입니다. 또한, 계속해서 바뀌는 값을 array에 넣어도 infinite loop가 발생합니다. 아마 하나 하나씩 제거하면서 찾아야 어떤 것이 문제였는지 알 수 있을 것 입니다.

하지만, 그렇게 하나하나씩 제거하는 것은 때때로 잘못된 수정방법이 될 수 있습니다. 그 방법 대신 근본적인 부분부터 고쳐나가세요.

예를 들어, 먼저 A 함수가 그 문제를 일으킨다면, 그 A 함수를 effects 안에 넣거나, 호이스팅 하거나, 또는 useCallback으로 감싸는 것이 도움이 될 수 있을 것 입니다.

object를 새로 재생성 하지 않으려면, useMemo를 유사한 용도로 사용할 수 있습니다.

4. 내 effect에서 왜 오래된 state나 props 값 이 나올까요?

effect들은 그것들이 정의되어있는 render에서 항상 props 과 state를 바라보고 있습니다. 그래서 이런 특징 덕분에 버그를 방지하는데 도움이 될 수 있지만, 몇몇 케이스들에서는 무시될 수 있습니다.

예를 들어, 변경될 수 있는 ref에서 몇몇 값을 명시적으로 유지해야 하는 상황처럼 말이죠. 만약 당신이 오래된 render에서 제대로된 props나 state를 바라보고 있다고 생각하지만, 기대한대로 동작하지 않는다면 아마 그것은 당신이 무조건 다른 의존성 있는 무언가를 놓쳤다는 것 입니다. 그럴 때는 lint rule 을 사용하여 그것들을 찾는 능력을 키우세요. 몇 일만 하다보면 자연스럽게 사용할 수 있을 것 입니다.
이 질문 도 참고해 보세요.


마치며

위 글을 읽지 않았다면, 단순히 effect를 Function Component에서 Lifecycle을 대체하려고만 사용할 수도 있었겠지만, useEffect가 추구하는 근본적인 모델, useEffect를 사용하면서 생길 수 있는 이슈들을 알아보니 lifecycle를 대체하는 것 이외에 useEffect의 목적에 맞는 유용한 기능들이 많은 것 같습니다.

의역과 오역이 정말 많은 와중에 끝까지 글을 읽어주셔서 감사합니다!
(고쳐야 될 부분이 있으면 댓글 또는 메일로 알려주시면 감사하겠습니다.)