![[React18] 디바운스(Debounce)와 스로틀(Throttle) 을 대체할 HOOK](https://nrw1yvstqytk8op6.public.blob.vercel-storage.com/posts/89a632b4-0832-4d40-85d5-db25c3be57d5/hero.png)
[React18] 디바운스(Debounce)와 스로틀(Throttle) 을 대체할 HOOK
디바운스(Debounce)와 스로틀(Throttle) 을 대체할 수 있는 react hook인 useDeferredValue와 useTransition를 알아보겠습니다.
React 18의 Concurrent Rendering: useDeferredValue와 useTransition
최신 React 버전인 React 18은 놀라운 성능 개선과 유연성을 제공하는 concurrent rendering 기능을 도입했습니다. 이를 통해 UI 업데이트와 상호작용을 더욱 부드럽게 처리할 수 있게 되었습니다. 이번 글에서는 React 18에서 도입된 중요한 변화 중 하나인 useDeferredValue와 useTransition 훅에 대해 알아보겠습니다.
Concurrent Rendering이란?
Concurrent Rendering은 React 18에서 새롭게 도입된 기능으로, 병렬 처리와 우선순위 조절을 통해 더 나은 사용자 경험을 제공합니다. 이전 버전에서는 UI 업데이트나 상태 변화가 발생하면 그 작업이 완료될 때까지 메인 스레드가 블록되는 문제가 있었습니다. 하지만 Concurrent Rendering은 작업의 우선순위를 조절하여 중요한 작업에 먼저 반응할 수 있도록 합니다.
useDeferredValue 훅
useDeferredValue 훅은 React 18에서 새롭게 도입된 훅 중 하나로, 값의 업데이트 우선순위를 조절하는 데 사용됩니다. 이전 값을 기억하면서도 업데이트를 지연시키므로, 메인 스레드가 블로킹되지 않으면서도 높은 우선순위의 작업을 처리할 수 있습니다.
예를 들어, 검색 자동완성 기능을 가진 애플리케이션에서 useDeferredValue를 활용하면 유저의 검색 쿼리가 변경되더라도 추천 검색어 업데이트가 늦어지지 않습니다. 이전 값을 유지하면서도 추천 검색어 업데이트를 지연시켜 유저 경험을 향상시킬 수 있습니다.
예제 1: 검색 자동완성
import { useState } from 'react'; import { useDeferredValue } from 'react'; function SearchBar() { const [query, setQuery] = useState(''); const deferredQuery = useDeferredValue(query); return ( <div> <input type="text" value={query} onChange={(e)=> setQuery(e.target.value)} /> <SearchSuggestions query={deferredQuery} /> </div> ); }
예제 2: 실시간 데이터 업데이트
import { useState } from 'react'; import { useDeferredValue } from 'react'; function RealtimeDataDisplay() { const [data, setData] = useState(''); const deferredData = useDeferredValue(data); // 데이터를 주기적으로 업데이트하는 함수 const fetchData = async () => { const response = await fetch('api/data'); const newData = await response.json(); setData(newData); }; return ( <div> <button onClick={fetchData}>새로운 데이터 가져오기</button> <DataDisplay data={deferredData} /> </div> ); }
useTransition 훅
useTransition 훅은 상태 변화의 우선순위를 지정하는 데 사용됩니다. isPending와 startTransition을 반환하며, isPending는 작업이 지연되고 있는지 여부를 나타내는 불리언 값이고, startTransition은 낮은 우선순위로 실행될 함수를 받습니다.
예를 들어, 버튼 클릭 시 상태 업데이트를 지연시키고, 그 동안 로딩 스피너를 표시하고자 할 때 다음과 같이 활용할 수 있습니다.
예제 1: 버튼 클릭 처리
import { useState } from 'react'; import { useTransition } from 'react'; function ButtonWithTransition() { const [isPending, startTransition] = useTransition(); const [count, setCount] = useState(0); const handleClick = () => { startTransition(() => { setCount((prevCount) => prevCount + 1); }); }; return ( <div> {isPending && <Spinner />} <button onClick={handleClick}>Increment</button> <p>Count: {count}</p> </div> ); }
예제 2: 로딩 상태와 데이터 표시
import { useState } from 'react'; import { useTransition } from 'react'; function LoadingAndDataDisplay() { const [data, setData] = useState(null); const [isPending, startTransition] = useTransition(); const fetchData = async () => { startTransition(() => { setData(null); // Reset previous data }); const response = await fetch('api/data'); const newData = await response.json(); startTransition(() => { setData(newData); }); }; return ( <div> <button onClick={fetchData}>Fetch Data</button> {isPending ? ( <p>Loading...</p> ) : ( <DataDisplay data={data} /> )} </div> ); }
디바운스와 스로틀링의 단점
디바운스와 스로틀링은 자주 발생하는 이벤트나 상태 업데이트를 제어하여 성능을 최적화하는데 사용되지만, 여전히 몇 가지 문제점을 가지고 있습니다.
디바운스의 단점
- 지연 시간 선택의 어려움: 디바운스에 사용할 지연 시간을 결정하기 어려울 수 있습니다. 지연 시간이 너무 짧으면 의도치 않게 빈번한 처리가 발생할 수 있고, 너무 길면 유저 경험이 느려질 수 있습니다.
스로틀링의 단점
-
불필요한 호출 제한: 스로틀링은 일정한 시간 간격으로 이벤트를 처리하여 불필요한 호출을 제한하나, 이로 인해 실제 이벤트가 놓치는 경우가 발생할 수 있습니다.
-
긴 시간 동안 이벤트 무시: 스로틀링된 함수가 일시적으로 비활성화되는 동안 긴 시간 동안 이벤트가 무시될 수 있습니다. 이는 사용자 경험에 악영향을 줄 수 있습니다.
useDeferredValue 와 useTransition의 장점
useDeferredValue의 장점
-
선별적인 업데이트: useDeferredValue는 값의 업데이트 우선순위를 조절하여 중요한 작업에 우선순위를 부여할 수 있습니다. 이를 통해 메인 스레드의 블로킹을 방지하면서도 높은 우선순위의 작업을 더 빠르게 처리할 수 있습니다.
-
고성능 상호작용: 유저 입력과 같이 중요한 상호작용에 대한 반응성을 높일 수 있습니다.
useTransition의 장점
-
상태 변화 우선순위 조절: useTransition을 활용하면 상태 변화의 우선순위를 지정하여 중요한 작업을 우선적으로 처리할 수 있습니다. 이로써 중요한 상호작용에 우선순위를 부여하면서도 백그라운드 작업을 놓치지 않게 됩니다.
-
부드러운 사용자 경험: 유저 입력과 같은 중요한 상호작용을 지연시키지 않으면서도 더 나은 성능과 부드러운 사용자 경험을 제공할 수 있습니다.
결론
디바운스와 스로틀링은 과거에 사용되던 성능 최적화 기술이지만, 그만큼 어려움과 문제점을 안고 있었습니다. React 18에서 도입된 useDeferredValue와 useTransition은 concurrent rendering을 통해 이러한 문제를 해결하고, 더 높은 성능과 유연성을 제공합니다. 디바운스와 스로틀링보다 훨씬 더 강력하고 정교한 처리를 가능하게 함으로써 사용자 경험을 더욱 향상시킬 수 있습니다.