Hone logo
Hone
Problems

Crafting a useGesture Hook in React

This challenge asks you to implement a custom React hook, useGesture, that provides basic gesture recognition capabilities (specifically, mouse movement tracking) within a React component. This hook will allow developers to easily track mouse position relative to an element and update state accordingly, enabling interactive elements like draggable components or custom controls. It's a valuable exercise in understanding React hooks and event handling.

Problem Description

You need to create a useGesture hook that takes a ref to a DOM element as input and returns an object containing:

  • x: The current x-coordinate of the mouse relative to the element.
  • y: The current y-coordinate of the mouse relative to the element.
  • isDragging: A boolean indicating whether the mouse is currently within the element.

The hook should:

  1. Attach mousemove and mouseleave event listeners to the provided DOM element.
  2. Calculate the mouse coordinates relative to the element's top-left corner.
  3. Update the x and y state variables whenever the mouse moves within the element.
  4. Set isDragging to true when the mouse enters the element and false when it leaves.
  5. Clean up the event listeners when the component unmounts to prevent memory leaks.

Key Requirements:

  • The hook must be written in TypeScript.
  • The hook must accept a ref to a DOM element.
  • The hook must return an object with x, y, and isDragging properties.
  • The calculations must be accurate and responsive.
  • The event listeners must be properly cleaned up.

Expected Behavior:

When the component mounts, the hook should attach the event listeners. As the mouse moves within the element, the x and y values should update in real-time. When the mouse leaves the element, isDragging should become false. When the component unmounts, the event listeners should be removed.

Edge Cases to Consider:

  • The provided ref might be null or undefined. Handle this gracefully (e.g., by returning default values or throwing an error).
  • The element might be removed from the DOM before the event listeners are cleaned up.
  • Performance considerations for frequent updates. While not a primary focus, avoid unnecessary re-renders.

Examples

Example 1:

Input: A ref to a <div> element with width 200px and height 100px. Mouse moves from (10, 20) to (150, 75) relative to the viewport.
Output: { x: 130, y: 55, isDragging: true }
Explanation: The x coordinate is calculated as 150 - 200px (viewport x) + 10px (element x) = 130px. The y coordinate is calculated as 75 - 100px (viewport y) + 20px (element y) = 55px. The mouse is within the element, so isDragging is true.

Example 2:

Input: A ref to a <div> element. The mouse leaves the element.
Output: { x: 0, y: 0, isDragging: false }
Explanation: The mouse is no longer within the element, so isDragging is false. x and y are reset to 0.

Example 3: (Edge Case)

Input: A null ref is passed to the hook.
Output: { x: 0, y: 0, isDragging: false }
Explanation: The hook handles the null ref gracefully by returning default values.

Constraints

  • The hook must be compatible with React 18 or later.
  • The element passed to the hook must be a valid DOM element.
  • The calculations should be accurate to within 1 pixel.
  • The hook should not introduce any significant performance bottlenecks (e.g., excessive re-renders).

Notes

  • Consider using useRef and useState hooks within your useGesture hook.
  • The getBoundingClientRect() method can be helpful for obtaining the element's position and dimensions.
  • Think about how to handle the case where the element is not yet available in the DOM when the hook is first called.
  • Focus on creating a clean, reusable, and well-documented hook. Error handling is important, but not the primary focus. The core functionality of tracking mouse position relative to an element is paramount.
Loading editor...
typescript