[이커머스 FE개발]버튼 중복 클릭 방지기능

이진규·2023년 4월 29일
0
post-thumbnail

Introduce

커머스 프로젝트에서 버튼에 중복 클릭을 방지하는 기능이 없다는 것을 깨달았다.
특히 API를 호출할 때는 중복 클릭을 방지하는 것이 필요하겠다 생각이 들어서 React에서는 어떻게 중복 클릭 방지 기능을 구현하는지 알아보고 직접 구현해보았다.

Flag 두기

일반적인 방식으로 Flag를 두고 API호출이 시작될 때 Flag를 false로 둬서 API호출을 막고 호출이 끝난 후 Flag를 true로 둬서 API호출을 허용하는 방식이다.

  let isApiCalling = false
  const handleOnclick = () => {
    if(isApiCalling){
      console.log("# API 호출중")
    }else{
      isApiCalling = true
      apiCall(...)
      .then(...)
      .finally(() => {
        isApiCalling = false
        ...
      })
    }
  }
  return(
    <>
        ...
      	<button onClick={handleOnclick}
   	  </>
	)

버튼클릭 후 Disable 시키기

Flag와 비슷한 방식이다. API 호출이 시작될 때 Button을 Disable시키고 호출이 끝난 후 Disable을 해제하는 방식이다.
Button을 Disable시키기 위해 useRef를 사용한다.

  const apiBtnRef = useRef<HTMLButtonElement>(null)
  const handleOnclick = () => {
    if (apiBtnRef.current) {
      apiBtnRef.current.disabled = true
      apiCall(...)
      .then(...)
      .finally(() => {
        if(apiBtnRef.current){
        apiBtnRef.current.disabled = false
      }
      ...
      })
  }
  return(
    <>
      ...
      <button ref={apiBtnRef} onClick={handleOnclick}
   	</>
  )

setTimeout 활용하기

둘 다 가능한 방법이지만, 마지막으로 클릭한 순간부터 API호출을 하고 싶다는 생각에 setTimeout과 clearTimeout을 활용해서 버튼을 한 번 클릭하고 일정 시간이 지나야 API 호출이 되고 지나기 전에 클릭되면 다시 그 시점부터 일정 시간이 지나야 API 호출이 되도록 구현해보았다.


const [id, setId] = React.useState<NodeJS.Timeout>()
const handleOnclick = () => {
  if(id){
    clearTimeout(id)      
  }
  setId(setTimeout(apiCall, 1000))
}
return(
  <>
    ...
    <button onClick={handleOnclick}
  </>

커스텀 훅 만들기

API호출이 있는 버튼마다 위의 코드를 추가하기에 너무 번거롭기 때문에 커스텀 훅으로 onClick 함수만 return 받아서 사용할 수 있도록 구현했다.

// usePrevDupClick.tsx
export type usePrevDupClickProp = {
  callBack: () => void,
  time?: number,
}
export const usePrevDupClick = ({callBack, time = 300}:usePrevDupClickProp) => {
  const [id, setId] = React.useState<NodeJS.Timeout>()
  const onClick = () => {
    if(id){
      clearTimeout(id)      
    }
    setId(setTimeout(callBack, time))
  }
  return {oneOnclick: onClick}
}

참고문헌

중복클릭 방지 로직과 useRef, kina님
중복클릭 방지 - 세마포어 이용하기, HyeonGuJ님
동작 아이콘 제작자: Freepik - Flaticon

profile
개발자

0개의 댓글