react-query 에서 useEffect 사용에 관한 질문 모음

Q&A 큐레이션

1. useEffect 관리하는 방법?

안녕하세요. react를 접한지 얼마 안 된 신입 개발자인데요. 기존 코드를 보고있는데 한 컴포넌트에 useEffect가 10 몇개씩 사용되고있는데, 이런식으로 사용하는게 맞는지 궁금합니다. 선언된 state를 보다가 state의 setter를 따라서 useEffect를 들어가다보면 어느샌가 코드 파일을 위 아래로 스크롤만 하고있고 코드가 뭐하는지 이해하기가 좀 어렵더라구요. 혹시 이렇게 비대한 컴포넌트를 이해하기 쉽게 effect를 관리하는 방법이 있나요? 또는 참고자료가 있다면 알려주세요. 감사합니다!


답변

코드를 보지 못해서 정확한 답변은 드리기 어렵지만 한 컴포넌트에 useEffect가 10개가 넘는게 일반적인 경우는 아닙니다. React.js 공식 문서의 조언에 의하면 useEffect는 마지막 수단으로 사용되어야 합니다. (https://beta.reactjs.org/learn/keeping-components-pure#where-you-_can_-cause-side-effects) useEffect를 제거할 때 고려해볼 수 있는 케이스는 아래와 같습니다. 1. API 요청을 통해 데이터를 불러오는 경우 데이터 요청 로직을 useEffect에서 할 수도 있지만, React Query같은 서버 상태 관리 도구를 쓰면 useEffect를 제거하고 간결한 코드를 유지할 수 있습니다. 2. 상태에 따른 부수효과를 처리하는 경우 이벤트 핸들러(onClick, onSubmit 등)에서 처리할 수 있는 로직을 useEffect로 처리하는 경우 이벤트 핸들러로 로직을 옮기는 것을 고려해볼 수 있습니다. 이벤트 핸들러에서 처리할 수 없는 로직인 경우 상태 설계를 잘못했는지 고려해봐야 합니다. 신입 개발자시라면 잘 이해가 안되실수도 있습니다. 아래 글들을 읽으면서 useEffect에 대한 개념을 먼저 정립해보시는걸 추천드립니다. useEffect 완벽 가이드 - https://overreacted.io/ko/a-complete-guide-to-useeffect/ useEffect가 나를 열받게 했다 - https://iborymagic.tistory.com/140

외 1개 답변 보러 가기

2. useEffect 의존성 배열

useEffect 안에서 사용되는 모든 상태값을 의존배열에 넣어야할까요? 제가 원하는 상태값만 넣었을 때는 정상적으로 기능이 작동하지만 es-lint 경고에 따라 사용하는 상태 값을 전부 넣었더니 원하지 않는 결과가 나옵니다…


답변

안녕하세요! 이부분은 저도 배재님과 같은 상황을 경험해보았고, 저또한 확실히 찾아보지않고 넘어갔던 부분이라서, 이번기회에 주변에 조언을 구해봤는데요! 제가 찾아본 바로 결론부터 말씀드리자면 린트에서 권고하는 사항처럼 디펜던시에 이펙트내에서 사용되는 state 들을 모두 넣어주는게 좋다 입니다! 배재님과 그리고 저도 겪었던, 이 상황이 발생하는 경우는 대표적으로는 state혹은 useEffect내 함수 설계미스일수 있다고 합니다! 간단한 해결방법으로는 강병진님께서 말씀해주신 disable 라인을 추가해주시는것도 방법이고, 혹은 로직을 리팩토링 해보는것도 좋으실 것 같습니다! 추가로 useEffect에 대한 좋은글이 있어 링크로 공유드립니다! 해당 글에서 배재님이 질문하신 내용도 세세히 다루고 있으니 읽어보시면 좋을것 같습니다~ https://velog.io/@khy226/useEffect-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%9A%94%EC%95%BD

외 6개 답변 보러 가기

3. useEffect 순서 관련 질문!

안녕하세요. useEffect의 순서는 parent -> child 순으로 된다고 알고 있는데 왜 그런지 혹시 설명해주실분 계신가요? 직접 console.log로 찍어보면 순서가 잘 돌아가는 것은 알겠는데 왜 이런 순서가 보장되는 것인지 이해가 잘 안되더라구요. 감사합니다!


답변

오잉 반대아닌가요? child -> parent 순인 것 같습니다. 간단히 설명하자면 작성하신 react 컴포넌트가 화면에 그려지기까지 여러 단계를 거치게 되는데요. 크게 render phase와 commit phase가 있습니다. render phase에서는 작성된 코드를 기반으로 어떻게 DOM을 수정해야할지 계산하는 단계고 commit phase에서는 실제 수정을 가하는 단계라고 생각하시면 될 것 같습니다. "useEffect의 순서가 어떻게 보장되나요?" 에 대한 답은 react가 작업 순서를 어떻게 정하는지 보면 될 것 같습니다. react는 각 컴포넌트를 react fiber node라는 객체로 변환을해서 render, commit phase를 수행하게 됩니다. react fiber node들은 linked list 형태로 저장이 되어 있어서 root fiber node에서 child fiber node까지의 순서가 보장됩니다. 비슷하게 useEffect도 effect list에 저장이되고 commit 단계에서 해당 effect list를 돌면서 useEffect를 수행하게 됩니다. 즉, 질문자님의 코드는 react에 의해서 아래의 과정을 거치게 될 것 같습니다. (편의를 위해 1단계 2단계로 나누겠습니다. render, commit phase와는 관계 없음) 1 단계: react fiber node 생성 단계와 effect list에 useEffect를 담는 과정 - App의 render 함수를 보니 ChildComponent라는 react fiber node를 생성하는 함수임. - ChildComponent의 render 함수를 보니 GrandChildComponent라는 react fiber node를 생성하는 함수임. - GrandChildComponent라는 react fiber node를 생성하면서 해당 컴포넌트 컨텍스트에서 돌아가는 코드 (useEffect와 기타 코드)를 보고 여러가지 메타 정보 및 commit 단계에서 실행해야할 함수를 react fiber node 객체에 저장함. useEffect의 경우는 hook이라는 객체로 생성이되고 effect list (작업 큐)에 담김 - ChildComponent도 위와 마찬가지 - App도 위와 마찬가지 1단계 종료시: - react fiber node는 App (root) -> ChildComponent (child node) -> GrandChildComponent (child's child node) 형태로 형성됨 - effect list는 [GrandChildComponent's useEffect, ChildComponent's useEffect, App's useEffect] 형태로 형성됨 2 단계: 작업 처리 과정 - App이라는 root fiber node를 기준으로 작업을 처리하기 시작함 - App의 render 함수를 실행하려고 보니 ChildComponent를 먼저 render 해야함. - ChildComponent도 GrandChildComponent를 먼저 render 해야함. - GrandChildComponent를 먼저 렌더하고, 해당 컨텍스트에 저장된 코드를 수행함 - ChildComponent도 위와 마찬가지 - App도 위와 마찬가지 - 렌더 후 effect list를 돌면서 effect들을 수행함 - effect list에 담긴 순서가 GrandChildComponent -> ChildComponent -> App 순이니 child -> parent 순으로 console.log 찍힘 저도 리액트 내부를 정확히 다 이해하고 있는 것은 아니니 대충 이런 느낌이다 정도로 참고하시면 될 것 같습니다. 더 정확한건 react source code를 직접보시거나 react fiber와 render, commit 단계를 설명해놓은 블로그들을 참고하시게 좋아보여요! 몇개 첨부해놓겠습니다 - https://www.bussieck.com/useeffect-under-the-hood/ - https://blog.logrocket.com/deep-dive-react-fiber/ - https://github.com/facebook/react - https://beta.reactjs.org/learn/render-and-commit

이 질문 바로 가기

4. 여러 개의 useEffect를 분기해서 설정할 때 문제가 있을까요?

다음과 같이 조건에 따라 다른 useEffect를 실행시키려고 합니다. const DataForm = (props: {condition, paramA, paramB} )=> { if (condition) { useEffect(() => { // handle param A }, [paramA]) } else { useEffect(() => { // handle param B }, [paramB]) } }; 이런식으로 작성하는 케이스를 별로 본 적이 없는 것 같은데 혹시 문제가 되거나 고려해야 할 부분이 있을까요?


답변

리액트 훅은 최상위에서만 호출되어야 한다는 규칙이 있습니다 https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level 작성하신 예시처럼 조건문 안에서 effect hook을 실행하면 에러가 발생할거에요. Effect hook 안에 조건을 작성하고 해당 조건을 충족하면 무언가를 실행하는 것이 맞습니다!

이 질문 바로 가기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

키워드로 질문 모아보기

실무, 커리어 고민이 있다면

새로운 질문 올리기

지금 가입하면 모든 질문의 답변을 볼 수 있어요!