useDeferredValue를 사용하며 발생하는 리렌더링의 과정 이해가 중요하다. 일단 초기 렌더링 중에는, 반환된 ‘지연된 값’은 사용자가 제공한 값과 동일하다(만약 준영을 먼저 input에 입력했다 가정). 업데이트가 발생하면 React는 먼저 이전 값(준영)으로 리렌더링을 시도(반환값이 이전 값과 일치하도록)하고, 그 다음 백그라운드에서 다시 새 값으로 리렌더링을 시도(ex. 준영 -> 준영2 입력 : 반환값이 업데이트된 새 값과 일치하도록)한다.
-> 결론적으로 렌더링을 2번 하는 것
공식문서 렌더링 과정 내용
❗중요 : 1. useDeferredValue의 값으로는 원시값(ex. 문자+숫자), 또는 컴포넌트 외부에 있는 객체이어야 한다. 렌더링 될 때마다 새로운 객체가 생성될 경우 불필요한 리렌더링이 발생하기 때문이다.
2. useDeferredValue 또한 Suspense와 같이 사용할 수 있다. 새 값으로 인한 백그라운드 업데이트가 변하는 경우로 인해 UI가 일시중단 될 경우 fallback 로딩을 제외할 수 있다.
3. React에서 useEffect 는 화면에 실제로 커밋된 이후에 실행된다. 즉, 값이 백그라운드에서 업데이트되는 동안에는 해당 값에 의존하는 useEffect는 실행 X. 이는 화면에 보이지 않는 변경 사항에 대해 불필요한 동작을 방지하기 위해서이다. 3번 같은 경우는 chatGPT한테 예시를 알려달라 했고 읽어보니 3번 내용이 더욱 이해가 잘 갔다. -> 결론: useEffect는 백그라운드에서 업데이트 되는 과정은 관심이 없고 백그라운드에서 업데이트 된 이후에 UI가 최신 반영되면 그때 useEffect가 발동 GPT한테 물어본 3번 내용의 예시
<값을 지연시키는 것의 작동과정>
작동과정에 대해서 더 궁금해져서 단계별로 한번 정리해보았다. 정리해볼 코드는 다음과 같다.
1단계 : React는 새 query 값으로 리렌더링하지만, deferredQuery는 이전 값을 유지한다. 즉, deferredQuery는 새 query 값보다 늦게 업데이트 된다.
2단계 : React는 백그라운드에서 query와 deferredQuery를 모두 업데이트된 값으로 리렌더링하려고 시도한다. 만약 데이터가 준비되지 않아 리렌더링이 일시 중단되면, React는 렌더링을 중단하고 데이터가 준비된 후 다시 시도한다. 즉, 결과적으로 사용자는 데이터가 준비될 때까지 이전의 지연된 값을 보게 된다.
❗주의할 점: 네트워크 요청 자체는 지연되는 것이 아니라 결과의 화면 표시가 지연되는 것이다. 즉, 화면에 표시되는 결과를 지연시키면서 최신 값을 기반으로 리렌더링을 수행해 성능을 최적화한다.
현재 코드는 타이핑되는 input의 값에 따라서 SlowList가 리렌더링 될 것이다. 일단 불 필요한 리렌더링을 막기위해 SlowList 컴포넌트를 memo로 감싸자. (props가 동일한 경우는 리렌더링 Skip 하도록)
-> memo로 감싸주어야 다시 렌더링 하는 동안 deferredText는 이전 값을 유지하고 있어, 즉시 SlowList를 다시 리렌더링할 필요가 없도록 할 수 있기 때문
하지만 여전히 문제점이 존재한다. memo로 감싸서 props가 변하지 않을 때 리렌더링을 방지할 수 있지만, props가 변할 때는 여전히 느릴 것이다(text가 변할 경우). 이때 useDeferredValue를 사용해 입력 필드는 즉각적으로 업데이트하면서, SlowList의 업데이트를 지연시켜 우선순위를 낮춘다면 타이핑이 끊기는 현상을 막을 수 있다.