Hone logo
Hone
Problems

React useOnScreen Hook: Visibility Detection

This challenge asks you to create a custom React hook, useOnScreen, that determines whether a given element is currently visible within the viewport. This hook is incredibly useful for triggering actions (like lazy loading images, animating elements, or tracking user engagement) only when an element is actually visible, improving performance and user experience.

Problem Description

You need to implement the useOnScreen hook in TypeScript. This hook should accept a ref to a DOM element as input and return a boolean value indicating whether the element is currently visible in the viewport. The hook should update this boolean value dynamically as the user scrolls.

Key Requirements:

  • Ref Input: The hook must accept a ref object (created using useRef) as its argument. This ref will be attached to the DOM element you want to monitor.
  • Visibility Detection: The hook must accurately determine if the element is visible in the viewport. An element is considered visible if at least a portion of it is within the viewport boundaries.
  • Dynamic Updates: The hook must re-evaluate the element's visibility on every scroll event.
  • Initial Value: The initial value returned by the hook should be false if the element is not initially visible.
  • TypeScript: The code must be written in TypeScript, with appropriate type annotations.

Expected Behavior:

  • When the component mounts, the hook should initially return false if the element is not visible.
  • As the user scrolls, the hook should continuously check the element's visibility.
  • When the element becomes visible, the hook should return true.
  • When the element scrolls out of view, the hook should return false.
  • If the ref is not attached to a DOM element, the hook should return false.

Edge Cases to Consider:

  • Element Not in DOM: Handle the case where the ref is not yet attached to a DOM element (e.g., during initial render or if the element is conditionally rendered).
  • Element Outside Viewport: Ensure the hook correctly identifies elements that are entirely outside the viewport.
  • Partial Visibility: The hook should return true if even a small portion of the element is visible.
  • Performance: Avoid unnecessary re-renders or calculations. Use debouncing or throttling if necessary to optimize performance.

Examples

Example 1:

Input: A div element with id="myDiv" initially outside the viewport.
Output: Initially false, then true when the user scrolls the div into view.
Explanation: The hook starts with `false` because the div is not visible.  Scrolling brings the div into view, causing the hook to return `true`.

Example 2:

Input: A div element with id="myDiv" initially visible in the viewport.
Output: true
Explanation: The hook immediately returns `true` because the div is already visible upon mounting.

Example 3: (Edge Case)

Input: A ref attached to a div that is conditionally rendered and initially not in the DOM.
Output: false (until the div is rendered and attached to the ref)
Explanation: The hook should return `false` until the div is actually present in the DOM and the ref is attached.

Constraints

  • Performance: The hook should not significantly impact the performance of the application. Avoid excessive re-renders. Consider using debouncing or throttling for the scroll event listener.
  • Browser Compatibility: The code should be compatible with modern browsers (Chrome, Firefox, Safari, Edge).
  • Input Type: The hook must accept a single argument: a React.RefObject<HTMLElement>
  • Return Type: The hook must return a boolean value.

Notes

  • You'll need to use ResizeObserver or window.addEventListener('scroll', ...) to detect changes in viewport size and scroll position. ResizeObserver is generally preferred for better performance and more accurate viewport detection.
  • Consider using a functional component and the useEffect hook to manage the scroll event listener and visibility checks.
  • Remember to clean up the event listener when the component unmounts to prevent memory leaks.
  • Think about how to handle the case where the ref is not yet attached to a DOM element. You might want to check if element is null or undefined before performing visibility calculations.
Loading editor...
typescript