React 18에서 useEffect
의 mount함수와 unmount함수가 두번씩 실행되는 현상이 발생했다.
React 공식문서에서는
앞으로 React가 상태를 유지하면서 UI의 섹션을 추가 및 제거할 수 있는 기능을 추가하고 싶습니다. 예를 들어, 사용자가 화면에서 멀어졌다가 뒤로 탭하면 React는 즉시 이전 화면을 표시할 수 있어야 합니다. 이를 위해 React는 마운트 해제 전에 사용된 것과 동일한 구성 요소 상태를 사용하여 트리를 다시 마운트하는 것을 지원합니다.
React 18은 Strict Mode에 대한 새로운 개발 전용 검사를 도입했습니다. 이 새로운 검사는 구성 요소가 처음으로 마운트될 때마다 모든 구성 요소를 자동으로 마운트 해제했다가 다시 마운트하여 두 번째 마운트에서 이전 상태를 복원합니다.
.
.
.
React가 상태를 유지하면서 UI 영역을 추가하거나 삭제 : 재사용가능한 상태 보장
ex) 탭 사이를 이동할 때 이전 탭의 상태를 유지하면 필수적이지 않은 API 호출과 같은 효과의 실행을 방지
재사용가능한 상태 보장하기 위해 트리를 여러번 마운트 해제하고 다시 마운트하는 과정에서 오류가 나지 않기 위해서 React는 component의 purity(순수성)가 더 중요해졌다.
처음엔 오류라고 생각했는데 React가 production mode의
Strict Mode
에서 컴포넌트의 순수성을 검사하기 위해 useEffect를 두 번 실행하는 것이었다.
오류가 아니기 때문에 해결이라고 할 건 아니지만 React Strict Mode를 해제하면 이러한 현상이 없어진다.
만약 컴포넌트가 순수하지 않다면?
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를 생성한다.
구성요소는 렌더링 중에 다른 구성 요소와 의존성을 가지면 안된다. 구성 요소는 자체적으로 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를 반환하기 때문에 순수하다.
useEffect
를 사용한다.