개발을 진행하다보면 input의 onChange 또는 scroll에 관련 이벤트를 연결하는 경우가 종종 있다. 만약에 input의 onChange에 API를 요청하는 이벤트가 걸려있다고 가정해보자. "hello"라는 다섯글자에 총 5번의 API 요청이 실행된다. 아무리 생각해도 너무 비효율적이다. 따라서 연이어서 호출되는 이벤트 중 마지막 이벤트만 실행되도록 구현해보자. 사실 debounce는 throttle과 떼어놀 수 없는 사이이지만, 이번 포스팅에서는 debounce에 대해서 다루고, 다음에 기회가 되면 예제와 함께 throttle에 대해서 다뤄보는 시간을 가지도록 하겠다.
debounce 란?
debounce는 사실 전자 공학에서 유래된 용어이다. 스위치 센서나 터치 센서를 다룰 때, 순간적으로 센서의 접점이 여러번 반복되어 on/off 되는 현상을 bouncing 현상이라고 한다. 이 여러번 반복되어 on/off 되는 현상을 무시하기 위해 특정 시간동안 판단을 지연하고, 정해진 시간 이후에도 on/off라면 해당 상태라고 판단한다. 이 현상을 자바스크립트에 적용한다면, 여러 번 실행되는 이벤트가 있다면 특정 시간동안 실행하지 않고, 정해진 시간 이후에 해당 이벤트를 한 번만 실행할 수 있게 된다.
debounce 훅
import { useEffect } from 'react';
const useDebounce = (callback: () => Promise<void>, delay: number) => {
useEffect(() => {
const timer = setTimeout(callback, delay);
return () => {
clearTimeout(timer);
};
}, [callback, delay]);
};
export default useDebounce;
debounce 훅은 위와 같이 구현했다. 자 그럼 코드를 한 번 살펴보자.
useDebounce는 인자로 일정 시간 후 실행될 콜백 함수와 콜백 함수가 실행되는 것을 기다릴 딜레이 시간을 받는다.
딜레이 시간이 지나기 전에 또 다른 이벤트가 발생한다면, clearTimeout을 통해 처음에 생성된 타이머를 취소한다. useEffect의 deps로 넣어준 콜백 함수를 통해 onChange마다 실행되는 콜백 함수에 따라 타이머가 취소되고, 생성되는 것이 반복된다.
useDebounce 사용
import memberApi from '@apis/member/memberApi';
import NavBar from '@components/common/NavBar';
import PageLayout from '@components/layout/PageLayout';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import useDebounce from '@hooks/useDebounce';
const Edit = () => {
const {
watch,
register,
handleSubmit,
formState: { errors },
} = useForm<FormValue>({ mode: 'onChange' });
const value = watch('nickname');
const validateNickname = async () => {
const { status } = await memberApi.getNicknameValidate(value);
};
useDebounce(validateNickname, 300);
return (
<PageLayout>
<EditContainer>
<EditLabel>변경할 닉네임</EditLabel>
<EditInputBox>
<EditInput
placeholder="변경 할 닉네임을 입력해주세요."
{...register('nickname', {
required: true,
pattern: {
value: /^[가-힣A-Za-z0-9]{2,10}$/g,
message: '최소 2자 ~ 최대 10자 까지 입력 가능합니다.',
},
})}
maxLength={10}
type="text"
className={value ? 'border-text-strong' : 'border-text-assitive'}
/>
</EditInputBox>
</EditContainer>
</PageLayout>
);
};
export default Edit;
나는 onChange 대신 react-hook-form의 watch를 사용하여 value를 추적했다. watch를 사용하면 리렌더링이 일어나면서 콜백 함수 또한 리렌더링이 일어나고 다른 콜백함수를 참조하게 되면서 useDebounce의 useEffect내에 callback이 계속 업데이트가 된다.
위에서 볼 수 있는 구현 결과는 다음과 같다. 마지막 타이핑에 닉네임 중복확인 API 요청이 한 번 실행되고, 중복된 닉네임인 경우 버튼이 비활성화 된다.
이렇게 오늘은 debounce와 debounce를 훅으로 만든 useDebounce에 대해서 알아보았고, 해당 훅을 사용하는 방법에 대해서도 알아보았다. 다음에는 이 포스팅 처음에 언급했던 것처럼 throttle에 대해서도 다뤄보는 시간을 가져보도록하겠다.
'개발' 카테고리의 다른 글
[개발] nextjs에서 모달 관리하기 (feat. recoil) (0) | 2023.05.08 |
---|---|
[개발] 페이지 접근 제한 구현 (0) | 2023.04.17 |
[개발] Nextjs Script 컴포넌트 사용 방법 (feat. 카카오맵) (0) | 2023.04.05 |
[개발] 카카오 로그인 구현하기 (0) | 2023.03.27 |
Yarn-berry + NextJS(typescript) 보일러플레이트 만들기 (0) | 2023.03.05 |