Hone logo
Hone
Problems

React useWakeLock Hook Challenge

Build a custom React hook, useWakeLock, that leverages the Web Wake Lock API to prevent device screens from dimming or locking. This is incredibly useful for applications where users need to keep the screen on, such as during long-form data entry, presentations, or gaming.

Problem Description

Your task is to create a reusable React hook named useWakeLock that allows components to acquire and release a screen wake lock. The hook should manage the state of the wake lock and provide functions to request and release it.

Key Requirements:

  1. Hook Signature: The hook should be a function useWakeLock(): { isLocked: boolean; requestLock: () => Promise<void>; releaseLock: () => void; error: Error | null }.
  2. State Management: The hook should expose a boolean isLocked to indicate if a wake lock is currently active.
  3. Requesting a Lock: It should provide a requestLock function that attempts to acquire a screen wake lock. This function should return a Promise that resolves when the lock is successfully acquired, or rejects if an error occurs or the API is not available.
  4. Releasing a Lock: It should provide a releaseLock function that releases the currently held wake lock.
  5. Error Handling: The hook should expose an error property (of type Error | null) to store any errors encountered during the process (e.g., API not supported, permission denied).
  6. API Availability Check: The hook should gracefully handle cases where the Wake Lock API is not supported by the browser.
  7. Resource Cleanup: When the component using the hook unmounts, any active wake lock should be automatically released to prevent resource leaks.

Expected Behavior:

  • Initially, isLocked should be false, and error should be null.
  • Calling requestLock() should attempt to acquire the lock. If successful, isLocked becomes true. If it fails, isLocked remains false, and error is updated.
  • Calling releaseLock() should release the lock. If successful, isLocked becomes false.
  • If the Wake Lock API is not available, requestLock() should reject immediately, and error should reflect this unavailability.

Edge Cases to Consider:

  • Browser does not support the Wake Lock API.
  • User denies permission to acquire the wake lock (though the API itself doesn't typically prompt for permission in the same way as other APIs, it can fail if the system is under heavy load or due to other OS-level restrictions).
  • Calling releaseLock() when no lock is currently held.
  • Component unmounting while a lock is active.

Examples

Example 1: Basic Usage

import React from 'react';
import useWakeLock from './useWakeLock'; // Assuming useWakeLock is in this path

function MyComponent() {
  const { isLocked, requestLock, releaseLock, error } = useWakeLock();

  return (
    <div>
      {error && <p style={{ color: 'red' }}>Error: {error.message}</p>}
      <p>Wake Lock Status: {isLocked ? 'Active' : 'Inactive'}</p>
      <button onClick={requestLock} disabled={isLocked || !!error}>
        {isLocked ? 'Lock Active' : 'Request Lock'}
      </button>
      <button onClick={releaseLock} disabled={!isLocked}>
        Release Lock
      </button>
    </div>
  );
}

Explanation:

This example demonstrates how a component can use useWakeLock. It displays the lock status and provides buttons to request and release the lock. The buttons are disabled appropriately based on the current state and potential errors.

Example 2: Handling API Not Available

If the browser doesn't support navigator.wakeLock, requestLock will reject, and the error state will be populated.

// ... (inside MyComponent from Example 1)

  React.useEffect(() => {
    // Imagine this is how you might initially try to lock, or inform the user
    const attemptLock = async () => {
      try {
        await requestLock();
        console.log('Wake lock acquired!');
      } catch (e) {
        console.error('Failed to acquire wake lock:', e);
        // The error state is already managed by the hook
      }
    };

    // Only attempt if lock isn't already active and no error
    if (!isLocked && !error) {
      attemptLock();
    }

    return () => {
      // Clean up on unmount
      releaseLock();
    };
  }, [isLocked, error, requestLock, releaseLock]);

// ... rest of the component

Explanation:

This snippet shows how the error property would be used. If requestLock fails due to API unavailability or any other reason, the error object will contain details, allowing the UI to inform the user. The useEffect demonstrates a common pattern of attempting to acquire a lock upon component mount and ensuring cleanup.

Constraints

  • The Wake Lock API (navigator.wakeLock.request) must be used.
  • The hook should be written in TypeScript.
  • The hook should handle potential DOMException errors thrown by the Wake Lock API.
  • Performance: The hook should be efficient and not introduce unnecessary re-renders.

Notes

  • The navigator.wakeLock.request() method takes an optional options object. For this challenge, you can focus on requesting a 'screen' wake lock.
  • Consider how to properly handle the promise returned by navigator.wakeLock.request().
  • Remember that the Wake Lock API is asynchronous.
  • Think about the lifecycle of a React component and how to ensure the wake lock is released when it's no longer needed or when the component unmounts.
Loading editor...
typescript