오스냅! React에서 디바운싱으로 검색 성능 최적화

"오스냅!"시리즈는 오늘 적용할 수 있는 작은 팁을 탐색합니다.


TL; DR



효율적인 방법으로 검색 필드가 있는 API를 쿼리하는 것은 생각만큼 어렵지 않습니다. 오늘 우리는 useRef()useState() React 후크를 사용하여 quickly denounce API calls하는 방법을 배웁니다.

시나리오



우리는 React 영화 앱을 위한 놀라운 반응 검색 기능을 만들었습니다. ( See the full app )

입력하는 동안 React는 입력 값을 보고 즉시 OMDB API를 쿼리하여 영화 목록을 반환합니다. 효과는 실행을 위해 별도의 "제출"버튼이 필요하지 않은 "라이브 검색"입니다. 꽤 놀랍습니다!




문제



우리가 보고 있지 않은 것은 React가 키를 누를 때마다 API에 대한 네트워크 호출을 한다는 것입니다.

즉, "Harry Potter and the Deathly Hallows Part 1"을 찾으려면 43개의 별도 네트워크 요청이 필요합니다.

성능 문제 외에도 키를 누를 때마다 새 정보가 나타나는 것은 너무 반응적이고 혼란스러울 수 있습니다.




왜 이런 일이 발생합니까?



React의 경우 onChange 함수를 통해 입력 값을 캡처하고 상태에 저장합니다. 그런 다음 우리useEffect는 상태가 업데이트될 때마다 API를 호출합니다.

// State that captures the user's input value
const [userSearch, setUserSearch] = useState(null);

// Makes an API request whenever the search state is updated
useEffect(() => {
  const query = `https://www.omdbapi.com/?s=${userSearch}&apikey=yourKey`;

  axios.get(query)
    .then(res => {
      // Execute next steps
    })

}, [userSearch]);

// JSX for the search field
<input
  type="text"
  value={userSearch}
  onChange={event => setUserSearch(event.target.value)}
/>


이렇게 하면 "라이브"검색 효과가 가능하지만 성능이 많이 저하됩니다. 이 기능은 너무 멋져서 onClick 해결 방법을 위해 포기할 수 없기 때문에 더 나은 솔루션이 필요합니다.


해결책



여기에서 "디바운싱"이 시작됩니다. 디바운싱은 특정 조건이 발생할 때까지 기능 작동을 지연시킵니다. (일반적으로 경과 시간입니다.)

이를 통해 모든 조건(사용자 입력)이 완료될 때까지 리소스 사용량이 많은 작업을 지연(API 호출)할 수 있습니다.

사용자 정의 후크 생성을 포함하여 이를 수행하는 많은 방법이 있습니다. 하단에 몇 가지 링크를 포함하여 더 자세히 살펴보겠습니다. 하지만 오늘 보여드릴 버전은 정말 심플해서 마음에 듭니다.

디바운스된 새 코드




// State that captures the user's input value
const [userSearch, setUserSearch] = useState(null);

// Holds a reference the current input field value
const inputRef = useRef(null);

// Makes an API request whenever the search state is updated
useEffect(() => {

  // Debounce Effect
  // Code within the setTimeout runs every 0.5 seconds
  const timer = setTimeout(() => {

    // 1. The conditional checks the input's current value
    // 2. It compares it against the userSearch state
    // 3. If they match then the user has stopped typing and the API is ready to be called 

    if(inputRef.current.value === userSearch) {
      const query = `https://www.omdbapi.com/?s=${userSearch}&apikey=yourKey`;

      axios.get(query)
        .then(res => {
          // Execute next steps
        })
    }
  }, 500)

  // Every time the useEffect runs it creates a new setTimeout function
  // Returning this cleanup function will run before each new render and remove the old timer
  return () => {
    clearTimeout(timer)
  }  

}, [userSearch, inputRef]);

// JSX for the search field
<input
  type="text"
  value={userSearch}
  onChange={event => setUserSearch(event.target.value)}
  ref={inputRef} // <--- ref grabs the input element 
/>


결과





그리고 API 요청이 실행되기 전에 타이핑이 완료될 때까지 기다립니다. 성능을 크게 절약하고 시각적으로 덜 혼란스럽습니다. 행복한 코딩!


자원


  • Debounce in JavaScript — Improve Your Application’s Performance
  • 좋은 웹페이지 즐겨찾기