[개발일지 #3] UseEffect는 왜 두번 실행되는걸까?

김유진·2022년 7월 29일
9

React

목록 보기
21/64
post-thumbnail
post-custom-banner

팀원들과 카카오 로그인 구현 중.. 인가코드를 자꾸 두 번 보내게 되는데, 그 원인을 몰라서 한참을 해메다가 UseEffect 때문에 이러한 문제가 발생되는 것을 알 수 있었다.

왜 날...괴롭히는거임

아무튼, useEffect의 기능을 다시 한 번 생각해보면서 이 문제를 해결해보려고 한다.

1. UseEffect란 무엇인가?

useEffect는 리액트 컴포넌트가 랜더링이 될 때마다 특정 작업을 수행하도록 설정할 수 있는 Hook이다.

1-1 마운트 될 때만 실행하고 싶어~

useEffect에서 설정한 함수가, 컴포넌트가 화면에 가장 먼저 렌더링 될 때만 실행되고, 업데이트를 하고 싶다면 두번째 파라미터로 비어 있는 배열을 넣어주면 된다.

  useEffect(() => {
    console.log('마운트 될 때만 실행됩니다.');
  }, []);

1-2 특정 값이 업데이트 될 때만 사용하고 싶어~

useEffect를 사용할 때, 특정 값이 변경이 될 때만 호출하게 하고 싶을 경우가 있다면 먼저 클래스형 컴포넌트를 다음과 같이 작성해보자.

componentDidUpdate(prevProps, prevState) {
  if (prevProps.value !== this.props.value) {
    doSomething();  
  }
}

위 코드에서는 props 안에 들어 있는 value 값이 바뀔 때에만 특정 작업을 수행하도록 하는데, 이것을 useEffect에서 해야 한다면 어떻게 해야 할까?
useEffect에 두번째 파라미터로 전달되는 배열 안에 검사하고 싶은 값을 넣어주면 된다.
아래와 같이 수정을 해보자.

useEffect(() => {
    console.log(name);
  }, [name]);

배열 안에는 useState를 통하여 관리하고 있는 상태를 넣어주어도 되고, props로 전달받은 값을 넣어주어도 된다.

정리하자면
useEffect는 기본적으로 랜더링 되고 난 직후마다 실행되며, 두번째 파라미터 배열에 무엇을 넣느냐에 따라서 실행되는 조건이 달라진다.

만약 컴포넌트가 언마운트되기 전이나, 업데이트되기 직전에 어떠한 작업을 수행하고 싶다면 useEffect에서 뒷정리 함수를 반환해주어야 한다.

 useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  });
import React, { useState } from 'react';
import Info from './Info';

const App = () => {
  const [visible, setVisible] = useState(false);
  return (
    <div>
      <button
        onClick={() => {
          setVisible(!visible);
        }}
      >
        {visible ? '숨기기' : '보이기'}
      </button>
      <hr />
      {visible && <Info />}
    </div>
  );
};

export default App;

랜더링이 될 때마다 뒷정리 함수가 계속 호출됩니다. 뒷정리 함수가 호출될 때에는 업데이트 되기 직전의 값을 보여주고 있다.
만약 오직 언마운트 될 때만 뒷정리 함수를 호출하고 싶다면, useEffect 함수의 두번째 파라미터에 비어있는 배열을 넣으면 된다.

useEffect(() => {
    console.log('effect');
    console.log(name);
    return () => {
      console.log('cleanup');
      console.log(name);
    };
  }, []);

그래서 UseEffect가 왜 두번 실행되었냐고? 결론을 이야기해라!

결론을 생각보다도 너무 간단한 문제였다... 정말 모든 개발자분들께 글을 써주셔서 넘너무 감사하다는 말을 전하고 싶다.

첫번째 시도

useEffect(() => {}, [])

위의 코드와 같이 useEffect 2번째 인자에 빈 배열을 넣어주게 되면 컴포넌트가 처음으로 랜더링 될 때만 실행된다고 한다.
그런데 왜.....
여전히 되지 않았다. 이것보다 더욱 근본적이 문제가 존재했던 것이다.

두번째 시도

두번째 시도는 바로, 프로젝트의 index.js 폴더에 문제가 존재했던 것이다.
<React.StrictMode> 태그로 <app/>이 감싸져 있었다는 것이다.

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>  // <= 이놈..
    <App />
  </React.StrictMode>   // 
);

이것을 지우니까 단박에 해결되었다. 그럼 여기서 궁금증, 도대체 쟤는 왜 존재하는 것일가?

React의 Strict Mode는 무엇일까?
StrictMode는 리액트에서 제공하는 검사 도구이다. 개발 모드일때 디버그를 통하여, 이 태그로 감싸져있는 App 컴포넌트까지 다.. 자손을 검사하는 것이다. 안전하지 않은 생명 주기를 가진 컴포넌트, 권장되지 않은 부분, 배포 후 문제가 될 수 있는 부분들까지 미리 확인하는 친구이다.

내가 creat-react-app으로 이 앱을 만들었기 때문에 기본적으로 생성되어 랜더링을 두 번이나 했었던 것이다.
더 자세한 글을 리액트 공식문서를 참고해보자

post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 11월 2일

state 로 트리거 값 만들어가며 뻘짓 많이 하고 있었는데 StrcitMode 가 원인이였네요...
도움 많이 됐습니다. 감사합니다. :)

답글 달기