[React] react 18 useEffect 두 번 실행되는 이슈

newsilver·2022년 7월 11일
0

React

목록 보기
7/7
post-thumbnail

Issue

React 18에서 useEffect 의 mount함수와 unmount함수가 두번씩 실행되는 현상이 발생했다.

화면 기록 2022-07-18 오후 4 44 59

재사용 가능한 상태 보장

React 공식문서에서는

앞으로 React가 상태를 유지하면서 UI의 섹션을 추가 및 제거할 수 있는 기능을 추가하고 싶습니다. 예를 들어, 사용자가 화면에서 멀어졌다가 뒤로 탭하면 React는 즉시 이전 화면을 표시할 수 있어야 합니다. 이를 위해 React는 마운트 해제 전에 사용된 것과 동일한 구성 요소 상태를 사용하여 트리를 다시 마운트하는 것을 지원합니다.

React 18은 Strict Mode에 대한 새로운 개발 전용 검사를 도입했습니다. 이 새로운 검사는 구성 요소가 처음으로 마운트될 때마다 모든 구성 요소를 자동으로 마운트 해제했다가 다시 마운트하여 두 번째 마운트에서 이전 상태를 복원합니다.
.
.
.

React가 상태를 유지하면서 UI 영역을 추가하거나 삭제 : 재사용가능한 상태 보장

ex) 탭 사이를 이동할 때 이전 탭의 상태를 유지하면 필수적이지 않은 API 호출과 같은 효과의 실행을 방지

재사용가능한 상태 보장하기 위해 트리를 여러번 마운트 해제하고 다시 마운트하는 과정에서 오류가 나지 않기 위해서 React는 component의 purity(순수성)가 더 중요해졌다.

처음엔 오류라고 생각했는데 React가 production mode의 Strict Mode 에서 컴포넌트의 순수성을 검사하기 위해 useEffect를 두 번 실행하는 것이었다.

Solution

오류가 아니기 때문에 해결이라고 할 건 아니지만 React Strict Mode를 해제하면 이러한 현상이 없어진다.
화면 기록 2022-07-18 오후 4 44 08

Purity

  • React의 렌더링 프로세스는 항상 순수해야 한다.
  • 구성요소는 순수 함수여야 한다.
    • 구성요소는 렌더링 전에 존재했던 객체나 변수를 변경 해서는 안 된다.
    • 동일한 입력이 주어지면 항상 동일한 결과를 반환해야 한다.

참고

Side Effect

만약 컴포넌트가 순수하지 않다면?

let number = 0;

const Name = () => {
  number += 1;
  return <h1>newsilver {number}</h1>;
};

const NamesList = () => {
  return (
    <div>
      <Name />
      <Name />
      <Name />
    </div>
  );
};

export default NamesList;

Name 컴포넌트는 외부에서 선언된 number 변수를 재선언하여 사용하고 있다.

다른 컴포넌트(NamesList)가 Name을 호출하면 렌더링된 시기에 따라 다른 JSX를 생성한다.

스크린샷 2022-07-18 오후 6 29 56

Solution

구성요소는 렌더링 중에 다른 구성 요소와 의존성을 가지면 안된다. 구성 요소는 자체적으로 JSX를 계산해야 한다.

const Name = ({ number }: { number: number }) => {
  return <h1>newsilver {number}</h1>;
};

const NamesList = () => {
  return (
    <div>
      <Name number={1} />
      <Name number={2} />
      <Name number={3} />
    </div>
  );
};

이제 Name 컴포넌트는 각자의 prop으로 JSX를 반환하기 때문에 순수하다.

스크린샷 2022-07-18 오후 6 31 18

Recap

  • 렌더링 전에 존재했던 객체나 변수를 변경하지 않는다.
  • 렌더링은 언제든지 일어날 수 있으므로, 컴포넌트 간의 렌더링은 독립적이어야 한다.
  • props, state, context로 변경사항을 업데이트한다.
  • 이벤트 핸들러에서 변경할 것이 있다면, useEffect를 사용한다.
profile
이게 왜 🐷

0개의 댓글

관련 채용 정보