useDeferredValue
는 React18에 새로 나온 Hook으로, 리렌더링의 우선순위에 따라 의도적으로 렌더링을 지연할 수 있는 Hook입니다. useDeferredValue는 값의 업데이트 우선순위를 지정하여 우선순위가 높은 작업을 실행하는 동안 useMemo와 같이 기존의 값을 가지고 있으며 업데이트를 지연시키는 것입니다.
이러한 기능은 이후 챕터에서 다룰 debounce, throttle 과 비슷해 보이지만 useDeferredValue
Hook을 이용하면 딜레이 시간을 고정하지 않고 더 긴급한 요청이 끝난 후 바로 지연된 렌더링을 실행한다는 이점이 있습니다.
const deferredValue = useDeferredValue(value);
useDeferredValue
는 첫번째 인자로 지연하길 원하는 값을 받고 해당 값의 복사본을 리턴합니다.
브라우저에서 더 우선적으로 출력 되어야 할 값을 계산하는 동안 useDeferredValue
를 이용하여 DOM 트리에서 긴급하지 않은 부분의 리렌더링을 의도적으로 지연 시킬 수 있습니다.
예를 들어 현재 실행되는 렌더링이 input창과 같이 타이핑 즉시 화면에 반영 되어야 하는 렌더링이라면 React에서는 이러한 긴급한 렌더링을 완료하기 전까지는 지연된 값을 기존의 값으로 출력하다가, 긴급한 렌더링이 끝나면 새로운 값을 출력하는 것입니다.
간단한 예제를 통해 useDeferredValue 사용법을 알아보겠습니다.
import React, { useState } from 'react';
export default function App() {
let heavyArray = new Array(10000).fill(0);
const [type, setType] = useState(0);
const typeChange = (e) => {
setType(e.target.value);
};
return (
<div>
<input type="text" onChange={typeChange} />
{heavyArray.map(() => {
return <div>{type}</div>;
})}
</div>
);
}
위 코드는 input에 텍스트를 입력하면 같은 내용이 10000번 출력 되는 코드입니다. 간단한 코드지만 타이핑을 해보면 10000번의 계산을 하느라 값이 출력 되는 속도 뿐만 아니라 input창 내부의 렌더링 속도 또한 느린 것을 알 수 있습니다.
이 때 useDeferredValue
를 이용한다면 heavyArray
의 출력을 지연 시킬 수 있습니다.
import React, { useState, useDeferredValue } from 'react';
export default function App() {
let heavyArray = new Array(10000).fill(0);
const [type, setType] = useState(0);
let deferredType = useDeferredValue(type);
const typeChange = (e) => {
setType(e.target.value);
};
return (
<div>
<input type="text" onChange={typeChange} />
{heavyArray.map(() => {
return <div>{deferredType}</div>;
})}
</div>
);
}
같은 코드에서 useDeferredValue
를 사용한 deferredType
값을 넣어주면 type
값이 변경되는 시점이 지연되어 input창의 출력 속도가 현저히 빨리진 것을 확인할 수 있습니다. 즉, input창의 내부는 빠르게 변경되지만, 해당 값을 사용하여 출력 되는 요소들의 렌더링은 후에 처리될 수 있어 사용자 입력에 빠르게 대응할 수 있는 것입니다.
이처럼 useDeferredValue
를 이용하면 긴급한 렌더링을 우선적으로 실행하도록 원하는 값의 렌더링을 지연 시킬 수 있습니다. 하지만 useDeferredValue는 값의 우선순위만을 지정하기 때문에 자식 컴포넌트의 값이나 상태의 업데이트를 지연시키기 위해서는 useMemo 혹은 React.memo를 사용해야합니다.