데이터 테이블의 헤더에서 특정 컬럼에 대한 데이터를 서칭하는 기능을 만들던 도중 구현하게 된 디바운스 인풋 컴포넌트다.
debounced-input.tsx
// debounced-input.tsx
'use client'
import { useEffect, useState } from 'react'
import { cn } from '@/libs'
import { Input } from './input'
interface DebouncedInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
className?: string
value: string | number
onDebounceHandler: (value: string | number) => void
debounce?: number
}
export const DebouncedInput = ({
className,
value: initialValue,
onDebounceHandler,
debounce = 500,
...props
}: DebouncedInputProps): JSX.Element => {
const [value, setValue] = useState(initialValue)
useEffect(() => {
setValue(initialValue)
}, [initialValue])
useEffect(() => {
const timeout = setTimeout(() => {
onDebounceHandler(value)
}, debounce)
return () => clearTimeout(timeout)
}, [value, debounce, onDebounceHandler])
return (
<Input
className={cn(className)}
{...props}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
)
}
page.tsx (사용 예시)
'use client'
import { FunctionComponent } from 'react'
import { DebouncedInput } from '@/components/shared/ui'
interface TestPageProps {}
const initialState = 'Input의 초기상태값'
const TestPage: FunctionComponent<TestPageProps> = ({}) => {
const callAfterDebounceTime = (value: string | number) => {
console.log('<Debounce Call>', value)
}
return (
<section>
<div className="m-auto w-[200px] py-2">
<DebouncedInput value={initialState} onDebounceHandler={callAfterDebounceTime} />
</div>
</section>
)
}
export default TestPage
사용이 그리 어렵지 않다.
동작원리
- 디바운스가 동작할 시간(debounce time)과 디바운스 시 실행될 함수(onDebounceHandler)를 디바운스 인풋 컴포넌트에 props 등을 활용하여 주입한다.
- Input 태그와 리액트의 state(여기서는 value state)를 연결하여 controlled component로 구성한다. 이는 키보드 입력시마다 컴포넌트를 리렌더링 시키기 위함이다. 물론 useRef를 이용하여 uncontrolled component로 구성할수도 있겠으나, 간단한 input 바인딩에는 useState를 사용하는 것이 더 명시적이라는 생각이 들기 때문에 이렇게 구성했다.
- useEffect와 setTimeout을 활용하여 onDebounceHandler가 debounce time 이후 실행될 수 있도록 해준다. useEffect에 타이머 정리함수를 반드시 명시해주는 것은 필수다.
- 핵심 동작 원리는 위와 같으며, 나머지는 알아서 커스터마이징하여 사용하면 된다.
흔하디 흔한 디바운싱 기능이지만 나름 react의 기능과 디바운싱을 이해해야만 자유자재로 구현할 수 있으므로 포스팅하기 좋겠다 싶어서 올려봤다.
나도 블로그에서 많은 도움을 받는 만큼, 앞으로는 구현했던 코드들을 간략히 정리하여 간간히 블로그에 포스팅할 생각이다.
'개발 일지' 카테고리의 다른 글
util) fetcher (fetch 래퍼) (0) | 2024.07.10 |
---|---|
React Hook) hover시 state를 변경하는 Hook (useHover) (0) | 2024.07.09 |
gitlab) runner has never contacted this instance (1) | 2024.05.27 |
VSCode에서 소스 코드 저장 시 eslint + prettier가 동작하지 않는 경우 (0) | 2024.04.07 |
프로젝트 설계 이모저모 - 프론트엔드 리포지토리 패턴 구현 (0) | 2024.02.29 |