useDeferredValue 란?
UI 일부의 업데이트를 지연시킬 수 있는 React 훅이다.
useDeferredValue, 언제 사용해야 할까
새 콘텐츠가 로드되는 동안 오래된 콘텐츠 표시하기
콘텐츠가 오래되었음을 표시하기
UI의 일부에 대해 리렌더링 연기하기
useDeferredValue의 구성
const deferredValue = useDeferredValue(value)
Parameters
value : 지연시키려는 값을 나타낸다. 어떤 타입이든 가질 수 있다.
Returns
초기 렌더링 중, 반환된 ‘지연된 값’은 사용자가 제공한 값과 동일하다.
업데이트 발생 시 React는 먼저 이전 값으로 리렌더링을 시도하고 백그라운드에서 다시 새 값으로 리렌더링을 시도한다.
사용시 주의사항
useDeferredValue
에 전달하는 값은 문자열 및 숫자와 같은 원시값이거나, 컴포넌트의 외부에서 생성된 객체여야 한다.
렌더링 중에 새 객체를 생성하고 즉시useDeferredValue
에 전달하면 렌더링할 때마다 값이 달라져 불필요한 백그라운드 리렌더링이 발생할 수 있다.useDeferredValue
가 현재 렌더링 외에 다른 값(Object.is
와 비교)을 받으면 백그라운드에서 새 값으로 다시 렌더링하도록 예약한다. 값에 대한 또 다른 업데이트가 있으면 백그라운드 리렌더링은 중단될 수 있으며 React는 백그라운드 리렌더링을 처음부터 다시 시작할 것이다.
ex) 차트가 리렌더링 가능한 지연된 값을 받는 속도보다 사용자가 input에 값을 입력하는 속도가 더 빠른 경우, 차트는 사용자가 입력을 멈춘 후에만 다시 렌더링된다.useDeferredValue
는<Suspense>
와 통합됩니다. 새 값으로 인한 백그라운드 업데이트로 인해 UI가 일시 중단되면 사용자에게 폴백이 표시되지 않는다. 데이터가 로드될 때까지 기존의 지연된 값이 계속 표시된다.useDeferredValue
는 그 자체로 추가 네트워크 요청을 방지하지 않는다.useDeferredValue
자체로 인한 고정된 지연은 없다. React가 원래의 리렌더링을 완료하자마자 React는 즉시 새로운 지연된 값으로 백그라운드 리렌더링 작업을 시작한다. 그러나 이벤트로 인한 업데이트(예: 타이핑)는 백그라운드 리렌더링을 중단하고 우선순위를 갖는다.useDeferredValue
로 인한 백그라운드 리렌더링은 화면에 커밋될 때까지 Effect를 실행하지 않는다. 백그라운드 리렌더링이 일시 중단되면 데이터가 로드되고 UI가 업데이트된 후에 해당 Effect가 실행된다.
사용법
1. 새 콘텐츠가 로드되는 동안 오래된 콘텐츠 표시하기
import { useState, useDeferredValue } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
// ...
}
초기 렌더링 시점에 지연된 값은 사용자가 제공한 값(value)과 동일하며 업데이트가 발생하면, 지연된 값은 최신 값보다 “뒤쳐지게” 된다. React는 먼저 지연된 값을 업데이트하지 않은 채로 렌더링한 다음, 백그라운드에서 새로 받은 값으로 다시 렌더링을 시도한다.
2. 콘텐츠가 오래되었음을 표시하기
위의 예에서는 최신 쿼리에 대한 결과 목록이 아직 로드 중이라는 표시가 없다. 새 결과를 로드하는 데 시간이 오래 걸리는 경우 오히려 사용자에게 혼란을 줄 수 있기 때문에
결과 목록이 최신 쿼리와 일치하지 않는다는 것을 사용자에게 더 명확하게 알리기 위해 오래된 결과 목록이 표시될 때 시각적 표시를 추가할 수 있다.
<div style={{
opacity: query !== deferredQuery ? 0.5 : 1,
}}>
<SearchResults query={deferredQuery} />
</div>
3. UI의 일부에 대해 리렌더링 연기하기
useDeferredValue
를 성능 최적화로 적용할 수도 있다.
UI의 일부가 리렌더링 속도가 느리고, 이를 최적화할 쉬운 방법이 없으며, 나머지 UI를 차단하지 않도록 하려는 경우에 유용하다.
function App() {
const [text, setText] = useState('');
const deferredText = useDeferredValue(text);
return (
<>
<input value={text} onChange={e => setText(e.target.value)} />
<SlowList text={deferredText} />
</>
);
}
이렇게 한다고 해서SlowList
의 리렌더링 속도가 빨라지지는 않는다.
하지만 키 입력을 차단하지 않도록 목록 리렌더링의 우선순위를 낮출 수 있다는 것을 React에 알려준다. 목록은 입력보다 지연되었다가 따라잡는다. 이전과 마찬가지로 React는 가능한 한 빨리 목록을 업데이트하려고 시도하지만, 사용자가 다시 입력하는 것을 차단하지는 않는다.