React.js 에서 useTransition 와 useDeferredValue 를 몰랐을 때에는 그냥 useEffect 혹은 useMemo 를 사용하여 state를 관리했었는데, 공식홈페이지를 보다가 조금 더 알게된 내용을 공부하고 포스팅한다.
0. useTransition 이란?
- 일반적인 상태 업데이트를 하는데 유용한 React Hook.
useFormStatus 와 유사하게 사용할 수 있다.
( useTransition: 일반적인 상태 업데이트, useFormStatus: Form 제출 상태를 관리)
const {isPending, startTransition} = useTransition()
이런 선언으로 간단하게 시작할 수 있다.
일반적인 textInput 값을 사용해보자
1. startTransition 으로 query의 값을 변경할 때 setQuery 호출
const [query, setQuery] = useState("");
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
startTransition(() => {
setQuery(e.target.value);
});
};
//컴포넌트 내용
return (
<input
type="text"
onChange={handleChange}
/>
)
1) useTransition은 상태 업데이트를 긴급하지 않은 작업으로 처리한다.
2) isPending 상태를 통해 전환 중임을 사용자에게 표시할 수 있다.
3) React는 더 중요한 업데이트(예: 사용자 입력)를 먼저 처리한 후 이 업데이트를 실행한다.
> Lazy Loading 과 같이 지연 연산으로 처리 한다.
> 만약 onChange 가 한 번 더 호출되면, 이전 연산하던 것은 버리고 새로 연산을 시작 한다.
2. defferredValue 선언
const defferredValue = useDeferredValue(query);
위에서 setQuery(newValue) 를 실행할때의 조건을 설정한다고 생각하면 된다.
1번과 마찬가지로 useDeferredValue는 값의 변경을 지연시켜 UI 응답성을 유지합니다.
사용자 입력에 즉시 반응하면서도 무거운 렌더링 작업은 나중에 처리할 수 있게 해줍니다.
3. 실제 Filter 처리
const list = Array.from({ length: 1000 }, (_, i) => `Item ${i + 1}`);
const filteredList = useMemo(() => {
if (defferredValue === "") return list; //공백일때는 초기화
return list.filter((item) =>
item.toLowerCase().includes(defferredValue.toLowerCase())
);
}, [defferredValue]);
실제로 사용할때는 query 값을 사용하는 것이 아니라, deferredValue 값을 사용해야한다. (지연처리를 위함)
추가적으로 useMemo 를 사용하였는데, 변경되지 않은 부분에 대해 불필요한 Re-Rendering 방지합니다.
결국, 궁극적 목표는 UI의 최적화이다. (버벅거림을 없애기)
전체 코드
const list = Array.from({ length: 1000 }, (_, i) => `Item ${i + 1}`);
const TransitionExample: React.FC = () => {
const [query, setQuery] = useState("");
const [isPending, startTransition] = useTransition();
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
startTransition(() => {
setQuery(e.target.value);
});
};
const defferredValue = useDeferredValue(query);
const filteredList = useMemo(() => {
if (defferredValue === "") return list; //공백일때는 초기화
return list.filter((item) =>
item.toLowerCase().includes(defferredValue.toLowerCase())
);
}, [defferredValue]);
return (
<>
<input
className="w-full h-10 px-4 py-3 mr-2 border border-gray-300 rounded-full focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent"
type="text"
onChange={handleChange}
placeholder="검색어를 입력하세요..."
/>
<ul className="divide-y divide-gray-200">
{filteredList.map((item) => (
<li
key={item}
className="py-2 px-3 hover:bg-gray-100 transition-colors duration-150 ease-in-out"
>
{item}
</li>
))}
</ul>
</>
)
TypeScript 로 연습했기 때문에 위와 같이 React.FC 같은 Type 선언이 추가되어져 있다.
'FrontEnd > React.js' 카테고리의 다른 글
[React-Query] 리액트 쿼리 사용해보기 - 캐싱을 통한 최적화 (0) | 2025.03.12 |
---|---|
[React.js] useContext / 테마색 바꾸기 (0) | 2025.03.11 |
[React] Streaming 처리하기 3 - abort 기능 추가 (0) | 2025.03.06 |
[React.js] Stream 데이터 fetch로 처리하기 - 2 (0) | 2025.02.28 |
[React.js] Stream 데이터 처리하기 - 1 (0) | 2025.02.27 |