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:
- Hook Signature: The hook should be a function
useWakeLock(): { isLocked: boolean; requestLock: () => Promise<void>; releaseLock: () => void; error: Error | null }. - State Management: The hook should expose a boolean
isLockedto indicate if a wake lock is currently active. - Requesting a Lock: It should provide a
requestLockfunction that attempts to acquire a screen wake lock. This function should return aPromisethat resolves when the lock is successfully acquired, or rejects if an error occurs or the API is not available. - Releasing a Lock: It should provide a
releaseLockfunction that releases the currently held wake lock. - Error Handling: The hook should expose an
errorproperty (of typeError | null) to store any errors encountered during the process (e.g., API not supported, permission denied). - API Availability Check: The hook should gracefully handle cases where the Wake Lock API is not supported by the browser.
- Resource Cleanup: When the component using the hook unmounts, any active wake lock should be automatically released to prevent resource leaks.
Expected Behavior:
- Initially,
isLockedshould befalse, anderrorshould benull. - Calling
requestLock()should attempt to acquire the lock. If successful,isLockedbecomestrue. If it fails,isLockedremainsfalse, anderroris updated. - Calling
releaseLock()should release the lock. If successful,isLockedbecomesfalse. - If the Wake Lock API is not available,
requestLock()should reject immediately, anderrorshould 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
DOMExceptionerrors 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 optionaloptionsobject. 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.