Hone logo
Hone
Problems

React Custom Hook: useSwipe

This challenge asks you to create a reusable React custom hook, useSwipe, that detects swipe gestures on a given element. Implementing this hook allows you to easily add swipe functionality to your React components, enabling features like horizontal scrolling, image galleries, or navigation controls. This is a common and useful pattern for creating interactive user interfaces.

Problem Description

You need to build a useSwipe hook that detects swipe gestures (both left and right) on a specified element. The hook should return an object containing a swipeLeft and swipeRight boolean flag, indicating whether a swipe in the respective direction has occurred since the last reset. The hook should also provide a resetSwipe function to reset the swipe flags to false.

Key Requirements:

  • Gesture Detection: The hook must accurately detect swipe gestures. A swipe is defined as a movement of at least minDistance pixels in a single direction (left or right) within maxTime milliseconds.
  • Directional Recognition: The hook must differentiate between left and right swipes.
  • Reset Functionality: The resetSwipe function must reset both swipeLeft and swipeRight flags to false.
  • Event Handling: The hook should handle the necessary event listeners (touchstart, touchmove, touchend) to detect the swipe gesture.
  • TypeScript: The hook must be written in TypeScript.

Expected Behavior:

  • When a swipe is detected, the corresponding flag (swipeLeft or swipeRight) should be set to true.
  • The flags should remain true until resetSwipe is called.
  • Multiple swipes in the same direction should not continuously set the flag to true. Once a swipe is detected, the flag remains true until reset.
  • The hook should not interfere with other event listeners on the element.

Edge Cases to Consider:

  • Short Movements: Movements shorter than minDistance should not be considered swipes.
  • Slow Movements: Movements that take longer than maxTime should not be considered swipes.
  • Multi-Touch: The hook should primarily focus on single-touch swipe detection. Handling multi-touch gestures is not required for this challenge.
  • Element Not Found: Handle the case where the element passed to the hook doesn't exist.
  • Unmounting: Properly clean up event listeners when the component unmounts to prevent memory leaks.

Examples

Example 1:

Input: Element: <div ref={elementRef}></div>, minDistance: 50, maxTime: 200
User swipes right across the element, covering a distance of 75 pixels within 150 milliseconds.
Output: { swipeLeft: false, swipeRight: true }
Explanation: A right swipe exceeding the minimum distance and within the maximum time is detected, setting swipeRight to true.

Example 2:

Input: Element: <div ref={elementRef}></div>, minDistance: 25, maxTime: 100
User swipes left across the element, covering a distance of 10 pixels within 50 milliseconds.
Output: { swipeLeft: false, swipeRight: false }
Explanation: The swipe distance is less than the minimum distance, so no swipe is detected.

Example 3:

Input: Element: <div ref={elementRef}></div>, minDistance: 30, maxTime: 300
User swipes right across the element, covering a distance of 60 pixels within 400 milliseconds.
Output: { swipeLeft: false, swipeRight: false }
Explanation: The swipe time exceeds the maximum time, so no swipe is detected.

Constraints

  • minDistance must be a positive integer (minimum: 1).
  • maxTime must be a positive integer (minimum: 1).
  • The hook should be performant and avoid unnecessary re-renders.
  • The element passed to the hook must be a valid DOM element.
  • The hook should not introduce any memory leaks.

Notes

  • Consider using useRef to store the element and the start position of the swipe.
  • Use addEventListener and removeEventListener to manage the event listeners.
  • Debouncing or throttling might be helpful to optimize performance, but is not strictly required for this challenge.
  • Focus on the core swipe detection logic and directional recognition. Styling or visual feedback is not required.
  • The elementRef should be a React ref object. The hook should accept this ref object as an argument.
Loading editor...
typescript