DEV Community

Cover image for useLongPress Custom Hook
Victor Hugo
Victor Hugo

Posted on • Edited on

useLongPress Custom Hook

Hello! My name is Victor Hugo and today i will show you why and how to use the useLongPress custom hook!

Events on frontend is the basic when you start to learn javascript, manipulating the DOM with clicks and forms is the basic, but sometimes we need something a litle bit more complex, a example is the double click that we can use the onDoubleClick event but what if we need to handle a long press, when the user click and hold the button, how do we handle this? This is the reason that we use the useLongPress hook!

First of all, let's start a new blank project, fell free to use any React framework that you want. I will use Vite with Typescript, if you're using Javascript just ignore the types, it will work in the same way.

Now that we already have create the project, let's create a folder named "hooks", in there we will store all custom hooks that we will create, in this example will be only one. We will create a new file with the name of the hook dot ts (useLongPress.ts), if you're using only javascript, the extension of the file need to be dot js (useLongPress.js).

Note that how it is a custom hook, it will not have any HTML and CSS inside only logic with typescript, that's why we're using the .ts extension and not .tsx.

folder named hook with one file inside

After that, we will create and export the hook with the state and refs that we will use in this hook, this is how it will looks like:

import { useRef, useState } from "react";

export function useLongPress() {
const [event, setEvent] = useState('')

  const isLongPress = useRef(false)
  const timerRef = useRef<ReturnType<typeof setTimeout>>()
}
Enter fullscreen mode Exit fullscreen mode

Now that we have setup everything that we will need to create this hook, let's make the first function of it:

function startPressTimer() {
    isLongPress.current = false
    
    timerRef.current = setTimeout(() => {
      isLongPress.current = true
      // this need to be here
      setEvent('longpress')
    }, 500)
  }
Enter fullscreen mode Exit fullscreen mode

This function will see the user click and will tell us if is a longpress or just a normal click.

How do he do that?

On every click he wil see if the user stop the click after 500 ms or not, if yes he will set the isLongPress ref as true, else it will be just a normal click and the ref will be false.

But how do he will know when the user will click?

We will create the functions that will do that:

function handleOnClick() {
    // click actions here
    setEvent('click')

    if (isLongPress.current) {
      // longpress actions here
      setEvent('longpress')
    }
  }

  function handleOnMouseDown() {
    startPressTimer()
  }

  function handleOnMouseUp() {
    clearTimeout(timerRef.current)
  }

  function handleOnTouchStart() {
    startPressTimer()
  }

  function handleOnTouchEnd() {
    clearTimeout(timerRef.current)
  }
Enter fullscreen mode Exit fullscreen mode

We will pass this functions to the onClick, onMouseDown, onMouseUp, onTouchStart and onTouchEnd events. Everytime the user touch or mouse down the button, it will trigger the startPressTimer function. The handleOnClick function is where we set the onClick event or longpress event, you can put specific logic inside and outside the if or just set the event state there like in this example.

The final step, return all this functions from the hook to we use whenever we want, it need to be exactly in this way:

return {
    event,
    handlers: {
      onClick: handleOnClick,
      onMouseDown: handleOnMouseDown,
      onMouseUp: handleOnMouseUp,
      onTouchStart: handleOnTouchStart,
      onTouchEnd: handleOnTouchEnd,
    },
  }
Enter fullscreen mode Exit fullscreen mode

In this way will be more easy to pass all the functions to the respectives events.

The final result will be like this:

import { useRef, useState } from "react";

export function useLongPress() {
  const [event, setEvent] = useState('')

  const isLongPress = useRef(false)
  const timerRef = useRef<ReturnType<typeof setTimeout>>()

  function startPressTimer() {
    isLongPress.current = false
    timerRef.current = setTimeout(() => {
      isLongPress.current = true
      // this need to be here
      setEvent('longpress')
    }, 500)
  }

  function handleOnClick() {
    // click actions here
    setEvent('click')
    if (isLongPress.current) {
      // longpress actions here
      setEvent('longpress')
    }
  }

  function handleOnMouseDown() {
    startPressTimer()
  }

  function handleOnMouseUp() {
    clearTimeout(timerRef.current)
  }

  function handleOnTouchStart() {
    startPressTimer()
  }

  function handleOnTouchEnd() {
    clearTimeout(timerRef.current)
  }

  return {
    event,
    handlers: {
      onClick: handleOnClick,
      onMouseDown: handleOnMouseDown,
      onMouseUp: handleOnMouseUp,
      onTouchStart: handleOnTouchStart,
      onTouchEnd: handleOnTouchEnd,
    },
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, how do we use this hook in any component?

I will show you:

function App() {
  const { event, handlers } = useLongPress()

  return (
{/* in this way we can pass all the functions to the respectives events in this button */}
    <button {...handlers}>
        ...
    </button>
  )
}
Enter fullscreen mode Exit fullscreen mode

Here is the example that i made:

gif with my example using the hook

Usefull links:

Video where i find this hook here:
Repository of this hook on Github:

Top comments (0)