React Hook으로 Blocking rendering 해결하기

Jay·2023년 1월 31일
0

Blocking rendering 🧱

한번 렌더링 연산이 시작되면 멈출 수 없는 문제이며 처리할 것이 많은 화면을 업데이트할 경우 렌더링 되는 동안 페이지가 지연되는 현상이 발생하는 것.

실시간 검색 기능을 구현하면서 다음과 같은 문제를 마주하게 되었습니다. 다음은 Blocking Rendering을 해결하지 않은 검색 기능입니다.

이 엄청난 불편함. 느껴지시나요?🥲
input창을 통해 state를 입력받고 업데이트 하며 해당 state를 n번 출력하도록 하고 있습니다. 이러한 경우 입력을 받을 때마다 state가 업데이트되어 n개의 div가 리렌더링 되기 때문에 큰 성능저하가 발생하게 됩니다.

Debounce? Throttle? 🤔

Debounce 는 이벤트를 그룹화하여 특정시간이 지난 후 하나의 이벤트만 발생하도록 하는 기술입니다.

해결책으로는 가장 먼저 디바운스를 떠올렸습니다. 하지만 디바운스는 단순히 작업을 뒤로 미루는 것일 뿐이라 유저가 계속해서 입력을 하는 경우라면 화면 업데이트가 계속해서 지연되는 이슈가 있었습니다. 또한 적절한 딜레이를 선택하는 것도 고민되었습니다. 딜레이가 너무 길면 유저 입력에 대한 반응도 그만큼 느려지지만, 너무 짧아도 적용하는 의미가 없어지기 때문입니다.

Throttle 은 이벤트를 일정한 주기마다 발생하도록 하는 기술입니다.

쓰로틀의 경우에는 일정 시간을 주기로 화면을 렌더링하도록 할 수 있겠지만, 그 일정 시간 내에 연속적으로 입력하는 것이 아니라 중간에 입력을 하지 않는 경우에는 무의미하게 기다리는 시간이 생기는 문제가 있었습니다.

useTransition 😮

저는 이 문제를 해결하기 위해 리액트 18에 새롭게 추가된 useTransition 훅을 사용해보았습니다. 리액트 18에는 상태 변화의 우선순위를 지정하기 위해 useTransition 훅이 새로 도입되었습니다. 

const [isPending, startTransition] = useTransition()

useTransition은 [isPending, startTransition]을 반환하는데, isPending 은 작업이 지연되고 있음을 알리는 boolean이며, startTransition 은 낮은 우선순위로 실행할 함수를 인자로 받습니다.

   <HeaderInput
              onKeyUp={(e) => {
                startTransition(() => {
                  setKeyword(e.target.value);
                });
              }}
              placeholder="계정 검색"
            />

startTransition으로 래핑된 업데이트는 급하지 않은 업데이트로 간주됩니다. 화면을 업데이트 하는 중에도 input 의 우선순위를 높여 입력이 끊기는 상황을 줄여줄 수 있었습니다.

다음은 useTransition을 사용하여 개선된 모습입니다.

디바운스나 쓰로틀과 비교하였을 때도 중간에 비어있던 시간들이 사라지기 때문에 UX가 더 좋아집니다. useTransition의 이점은 이뿐만이 아닙니다.작업이 지연되고 있음을 알리는 isPending의 boolean 값을 활용하여 로딩 중을 표시하는 ui를 띄워 손쉽게 ux를 향상 시킬 수도 있었습니다.

 return (
    <LayoutSection>
      <h2 className="sr-only">검색 결과</h2>
      <ResultsUl>
        {isPending ? (
          <ImageWrapper>
            <img src={loadingImage} alt="로딩 중" />
          </ImageWrapper>
        ) : (
          searchData.map((data, i) => (
            <Result {...data} keyword={keyword} key={data._id} />
          ))
        )}
      </ResultsUl>
    </LayoutSection>
  );

다음은 isPending의 값이 true일 때 loading gif를 띄워 UX를 향상시킨 모습입니다.


useTransition 훅은 이번에 문제를 마주하며 처음 사용해보았는데요, 간편한 hook으로 기능이 제공되기 때문에, 기존 로직에 아주 쉽게 적용할 수 있었습니다. 사용법을 조금 더 익혀서 앞으로도 유용하게 사용해 볼 예정입니다.

0개의 댓글