본문 바로가기
카테고리 없음

[React] 사용자 입력에 따른 검색 결과 업데이트 시 useTransition으로 사용자 경험 개선하기

by 2__50 2023. 12. 27.
공부한 내용을 정리한 글입니다 
내용에 오류가 있거나 더 좋은 의견이 있다면 댓글로 남겨주세요.
배움에 큰 도움이 됩니다. 🖋

 

 

useTransition으로 사용자 입력에 따른 업데이트 시 사용자 경험 개선하기


 

 

사용자가 검색어를 입력하면 추천 검색어를 띄워줄 때 처럼 사용자 입력에 따른 비동기 요청을 수행하는 경우, 이를 최적화 하는데는 여러 방법이 있다.

오늘은 react 18버전에 업데이트 된 useTransition() hook으로 사용자 경험을 개선해보고, 기존에 업데이트 지연을 위해 사용하던 debounce와는 어떤 차이점이 있는지 알아볼 것이다.

 

 

import { useState, useEffect } from 'react';

const SearchComponent = () => {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);

  const handleChangeInput = async (e) => {
  	const newQuery = e.target.value
	setQuery(newQuery)
    
    if (query.trim() === '') return
    try {
      const response = await fetch(`https://api.example.com/search?q=${newQuery}`);
      const data = await response.json();

      setResults(data);
    } catch (e) {
      console.error(e);
    }
  };

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={handleChangeInput}
        placeholder="검색어를 입력하세요"
      />
      <ul>
        {results.map((result) => (
          <li key={result.id}>{result.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default SearchComponent;

 

 

React 18 이전에는 모든 상태 업데이트의 중요도가 같았기 때문에 setQuery()도 setResults()도 모두 동일한 우선순위로 처리되었다. 만약 위의 코드가 아래처럼 1초에 2.7타씩 입력해버리는 사용자를 만나면 api요청 또한 1초에 3번씩 일어날 것이므로 input 창과 검색 결과 화면이 업데이트 될 때 사용자는 상당히 버벅거림을 경험할 것이다.

 

 

https://www.tajamaster.com/ex4_2.php

 

 

이럴 때 우리는 디바운싱을 이용하고는 했다. 디바운싱은 사용자의 입력이 끝나고 일정 시간이 지나면 화면을 업데이트하는 방식이다. 그렇기 때문에 사용자 입력이 계속된다면 화면 업데이트가 그만큼 지연될 수 있다.

 

 

+ Debounce, Throttle 시각화 데모 사이트

https://web.archive.org/web/20180910162350/http://demo.nimius.net/debounce_throttle/

 

 

 

 

 

 

Debounce

 

import debounce from 'lodash/debounce';

...

 const debouncedHandleChange = debounce(async (newQuery) => {
    try {
      const response = await fetch(`https://api.example.com/search?q=${newQuery}`);
      const data = await response.json();

      startTransition(() => {
        setResults(data);
      });
    } catch (error) {
      console.error(error);
    }
  }, 300);

  const handleChangeInput = (e) => {
    const newQuery = e.target.value;
    setQuery(newQuery);

    debouncedHandleChange(newQuery);
  };

...

 

 

반면 useTransition은 화면 업데이트 중에도 사용자 입력을 받을 수 있다.

상대적으로 우선순위를 낮추고 싶은 상태 업데이트를 startTransition()으로 감싸는 방식이다. 아래 코드처럼 검색 결과 업데이트의 우선순위를 낮추고 사용자 입력의 우선순위를 높히면 사용자 경험을 향상시킬 수 있다.

 

React 18부터는 화면을 렌더링하는 중에도 더 우선순위가 높은 작업이 생기면 그것을 먼저 처리할 수 있게 되었기 때문에 이런 작업이 가능해졌다.

 

 

useTransition

 

import { useState, useEffect, useTransition } from 'react';

const SearchComponent = () => {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  const handleChangeInput = async (e) => {
  	const newQuery = e.target.value
	setQuery(newQuery)
    
    if (query.trim() === '') return
    try {
      const response = await fetch(`https://api.example.com/search?q=${newQuery}`);
      const data = await response.json();
      // 검색 결과 상태 업데이트의 우선순위를 낮춤
      startTransition(() => {
        setResults(data);
      });
    } catch (e) {
      console.error(e);
    }
  };

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={handleChangeInput}
        placeholder="검색어를 입력하세요"
      />
      {isPending && <p>검색 중...</p>}
      <ul>
        {results.map((result) => (
          <li key={result.id}>{result.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default SearchComponent;

 

 

 

정리하기 _우선순위 작업 관점


useTransition
- 우선순위가 높은 작업이 들어오면 그것을 우선 처리하여 지연된 업데이트를 가능하게 한다.

 

Debouncing
- 일정 시간 동안 다른 호출이 없을 때에만 작업을 수행한다.
- 연속된 이벤트에서 불필요한 연산을 줄여 성능을 향상시킬 수 있으나, 작업의 우선순위에 대해 고려하지 않는다.


Throttling
- 정해진 주기마다 이벤트를 처리한다.
- 빈번한 이벤트를 제어하여 성능을 향상시킬 수 있으나, 작업의 우선순위에 대해 고려하지 않는다.

 

 

 

 

참고


https://react-ko.dev/reference/react/useTransition

 

useTransition – React

The library for web and native user interfaces

react-ko.dev

https://dev.to/perssondennis/react-hooks-usethrottledvalue-and-usethrottledfunction-1j2n?ref=dailydev

 

React Hooks: useThrottledValue and useThrottledFunction

This article explains the new React 18 hooks useDeferredValue and useTransition and compares them to...

dev.to

 

댓글