[react] useEffect 더 잘 쓰기

김학재·2023년 9월 13일
0

리액트

목록 보기
7/8
post-thumbnail

정의

useEffect는 리액트에서 제공하는 훅 중 하나로 컴포넌트를 컴포넌트 외부와 통신(synchronize a component with an external system)할 수 있도록 해주는 훅이다.

참고 링크 : Synchronizing with Effects

❓ Synchronize with external system?

💡 특정 컴포넌트들은 외부 작업과 동기화되어야 한다.
예를 들어, 리액트 상태(state)를 기반으로 non-react 컴포넌트를 조작하거나, 서버와 연결하거나, 컴포넌트가 화면에서 나타날 때 분석용 로그를 보내는 동작들이 포함될 수 있다.
Effect는 컴포넌트가 외부와 동기화될 수 있도록 렌더링 된 후에 코드를 실행할 수 있게 해준다. 클릭과 같이 액션이 따로 없어도 코드를 실행할 수 있게 한다.

기본적인 사용법

useEffect 훅을 사용하는 방법은 간단하다.

  1. Effect 정의하기
    렌더링과 동시에 실행될 작업을 정의한다

  2. Effect의 dependency 정의하기
    Effect는 필요한 순간에만 재실행되어야 한다. dependency가 제대로 정의되지 않으면 의도치 않은 무한 Effect가 발생할 수 있다.
    dependency에 빈 배열 [] 을 지정하면 리액트가 불필요한 Effect의 재실행을 하지 않도록 할 수 있다.

  3. 필요하다면 cleanup 진행하기
    특정 경우에 Effect는 정지 동작이 정의되어야 한다.
    예를 들어 connect - disconnect subscribe - unsubscribe ...

여기서 중요한 포인트는 Effect는 모든 렌더링마다 실행된다는 점이다. 즉 무한 실행을 방지하기 위해서는 dependency를 잘 정의해야 한다

useEffect 더 잘 쓰기

드디어 이번 포스팅에서 다루고자 하는 본격적인 내용이다.
react로 프로젝트를 진행하다 보면 특정 컴포넌트에서 서버와 통신을 위해 useEffect를 사용하는 경우가 있다.

아래 코드는 isEdit이 true인 경우 서버에서 정보를 가져오는 코드의 일부이다.

import { useState, useEffect } from react

...

const [isEdit, setIsEdit] = useState(false)

useEffect(() => {
  if (isEdit) {
    getData()
  }
}, []) // empty dependency array

하지만 여기서 dependency 배열이 비어 있으면 missing dependency warning을 마주하게 된다.

데이터를 가져오기만 한다면 문제가 없지만 가져온 데이터를 기반으로 컴포넌트가 변화하게 된다면 리액트는 다시 렌더링이 발생한 것으로 간주하고 다시 Effect를 실행한다. 이는 다시 렌더링을 일으키고 다시 Effect를...

해결 방법

1. 적절한 dependency 사용하기

대개의 경우 infinite loop 문제는 dependency를 잘못 사용해서 발생한다.

2. useCallback 사용하기
리액트의 훅 중 하나인 useCallback을 사용해 이를 해결할 수도 있다.

import { useEffect, useCallback } from 'react'

...
const [isEdit, setIsEdit] = useState(false)

const memoizedGetData = useCallback(() => {
  getData()
}, [])

useEffect(() => {
  if (isEdit) {
    memoizedGetData()
  }
}, [isEdit, memoizedGetData])
  

+ dependency가 없다니까!!
그러나.. 내가 마주한 문제는 dependency를 잘 주던, useCallback을 사용하던 자꾸 함수 그 자체를 missing dependency를 넣으라는 warning이었다.

useEffect(() => {
    if (isEdit) {
      getCurriculumInfo()
    }
  }, [])

useEffect missing dependency

getCurriculumInfo를 사용하는데 getCurriculumInfo를 dependency로 넣으라는 에러..

useCallback을 사용해도 이 warning은 해결되지 않아 결국 lint rule을 설정했다 (권장 X)

[ESLint] Feedback for 'exhaustive-deps' lint rule

그러나.. 근본적으로내 코드에 문제가 있다는 것을 알고 setState 로직을 변경해야 한다는 것을 글 말미에야 깨달았다..

결론은 getCurriculumInfo 함수 자체를 useEffect 콜백 함수 안으로 옮겨서 해당 warning을 해결할 수 있었다. 이렇게 함으로서 Effect의 outer scope가 아닌 local function으로 만들고, 리액트가 더 이상 dependency로 인식하지 않게 된다.
commit - getCurriculumInfo 함수를 useEffect 내부로 옮김

추가로 useCallback을 사용해서 코드를 좀 더 깔끔하고 안전하게 만들 수도 있다!
commit - getCurriculumInfo 함수를 useCallback hook에서 호출

결론

  • useEffect 훅은 컴포넌트가 컴포넌트가 아닌 동작과 동기화해서 작동하도록 한다
  • useEffect 훅은 dependency를 잘 지정해야 한다
  • Effect 의 scope을 잘 고려해서 함수의 위치를 지정해야 한다
profile
YOU ARE BREATHTAKING

0개의 댓글