마! 명령하지마라! 선언해라

정호진·2023년 12월 20일
1

React

목록 보기
3/4

React의 상태 보존

리액트 공식 문서를 읽으면서 번뜩이는 궁금증이 생겼습니다. state 보존 및 재설정에서 지역 상태의 위치는 리액트의 Value UI (Virtual DOM)의 위치에 따라 구분이 됩니다. 따라서 아래의 경우에 상태가 저장되지 않고 초기화되는 것을 알 수 있습니다.

여기서 해당 상태가 아예 초기화되는 이유는 간단합니다. 렌더링할 때 Value UI에서 카운터 대신에 다른 태그를 렌더링하기 때문입니다. 다시 변경 했을 때는 처음부터 렌더링이 되는 것이고 초기화 값인 0이 할당되는 것입니다.

이 결과는 어찌 보면 당연한 결과입니다. 애초에 카운터에 있는 값을 참조하고 있는 컴포넌트가 없어져 버리는 것이기 때문에 해당 값은 더 이상 메모리상에 존재할 필요 없는 데이터이기 때문이죠. 만약에 존재한다면 그게 더 이상한 문제를 야기할 수 있습니다. 즉 “동일한 위치에 다른 컴포넌트가 오게 된다면 컴포넌트는 초기화된다.”라는 결론이 나오게 됩니다.

조건부 렌더링을 사용하는 경우

조건부 렌더링을 사용하는 경우는 주로 비동기 처리를 할 때 그 상태에 따라 다른 UI를 보여주게 됩니다. 이 방법을 사용하는 예시 중 하나는 Fetch-on-Render 방식입니다.

function ProfilePage() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetchUser().then(u => setUser(u)); // 2
  }, []);

  if (user === null) {
    return <p>Loading profile...</p>; // 1
  }
  return ( 
    <>
      <h1>{user.name}</h1> // 3
      <ProfileTimeline /> // 4
    </>
  );
}

하지만 이 방법은 위에서 보여줬던 React 상태 보존 관점에서 하위 컴포넌트의 상태가 보존되지 않을 수 있는 단점이 있습니다. user의 상태에 따라 렌더링하는 컴포넌트가 달라지는데, user의 상태가 null이었다가 다시 값을 할당하게 된다면 기존에 있던 로컬 데이터는 모두 초기화되는 것입니다. 개발자의 의도에 따라 이전 상태 값을 초기화하고 싶을 수 있지만 그게 아니라면 기존에 있던 값을 상태 끌어올리기를 통해 데이터를 저장하는 등의 불필요한 방식을 적용할 수도 있습니다.

Suspense 또 너야?

그렇다면 이전 상태를 보존하면서 대체 UI를 보여주는 방법이 있을까요? 당연히 있습니다. 바로 Suspense입니다. 우선 아래 예시를 먼저 보겠습니다.

왼쪽 카운터가 Suspense로 감싼 컴포넌트고 오른쪽이 일반 조건부 렌더링을 적용한 것입니다. 결과는 왼쪽은 상태 보존, 오른쪽은 상태 초기화가 됩니다.

그렇다면 왜 Suspense는 상태 값을 초기화하지 않을까요? 바로 Value UI의 위치를 변경하지 않기 때문입니다.

Suspense는 리액트의 렌더링 순서를 후순위로 미루고 대체 UI를 띄워주는 것일 뿐 원래 자리에 렌더링 돼야 했을 컴포넌트의 위치에 해당 값이 렌더링 되지 않습니다. Suspense의 자식 컴포넌트들의 렌더링을 미리 전부 마쳐 놓고, 해당 컴포넌트가 promisethrow 하지 않을 때까지 대체 UI를 보여주기 때문입니다. 그리고 fallback UI를 렌더링하고 있는 도중에 하위 컴포넌트는 visible: hidden으로 설정하고 형제 컴포넌트로써 계속해서 렌더링하고 있는 것이기 때문에 위치에 변동이 없습니다.

결론: 비동기 렌더링 시에 지역 상태 관리 보존하기 위해서는 Suspense를 사용하면 좋다.

0개의 댓글

관련 채용 정보