React Screen Share Hook Implementation
This challenge asks you to implement a custom React hook, useScreenShare, that manages the lifecycle of screen sharing functionality within a React component. The hook should handle requesting screen sharing permission from the browser, starting and stopping the screen share stream, and providing a stateful mechanism for the component to know whether screen sharing is active. This is useful for building video conferencing or remote assistance applications.
Problem Description
The useScreenShare hook should provide the following functionality:
- Permission Request: Upon initial mount, the hook should request screen sharing permission from the user using the browser's
navigator.mediaDevices.getDisplayMedia()API. - State Management: The hook should maintain the following state variables:
isSharing: A boolean indicating whether screen sharing is currently active. Initiallyfalse.error: An error object if an error occurred during permission request or stream creation. Initiallynull.stream: TheMediaStreamobject representing the screen share stream. Initiallynull.
- Start Sharing: A function
startSharingthat, when called, attempts to start screen sharing. It should:- Check if screen sharing permission has already been granted. If not, it should request permission first.
- If permission is granted (or already exists), it should call
navigator.mediaDevices.getDisplayMedia()to obtain a screen share stream. - If successful, it should set the
streamstate to the obtained stream andisSharingtotrue. - If an error occurs, it should set the
errorstate to the error object.
- Stop Sharing: A function
stopSharingthat, when called, attempts to stop screen sharing. It should:- If
isSharingistrue, it should iterate through the tracks of thestream(if it exists) and calltrack.stop()on each track. - It should then set the
streamstate tonullandisSharingtofalse.
- If
- Cleanup: On unmount, the hook should ensure that the screen share stream is stopped if it's active, preventing potential resource leaks.
Expected Behavior:
- The hook should gracefully handle cases where the user denies screen sharing permission.
- The hook should handle errors that may occur during stream creation.
- The hook should correctly start and stop the screen share stream.
- The component using the hook should be able to react to changes in the
isSharing,error, andstreamstate.
Examples
Example 1:
Input: A React component using the useScreenShare hook. The user initially denies screen sharing permission.
Output: The component renders a message indicating that screen sharing permission was denied. The `isSharing` state is `false`, and the `error` state contains an error object.
Explanation: The hook correctly detects the denied permission and updates the state accordingly.
Example 2:
Input: A React component using the useScreenShare hook. The user grants screen sharing permission. The component calls `startSharing`.
Output: The component renders a video element displaying the screen share stream. The `isSharing` state is `true`, and the `stream` state contains the `MediaStream` object.
Explanation: The hook successfully requests permission, obtains the stream, and updates the state.
Example 3: (Edge Case - User revokes permission after granting)
Input: A React component using the useScreenShare hook. The user initially grants screen sharing permission. Later, the user revokes the permission in browser settings. The component calls `startSharing`.
Output: The component renders an error message indicating that screen sharing permission has been revoked. The `isSharing` state is `false`, and the `error` state contains an error object.
Explanation: The hook correctly detects the revoked permission and updates the state.
Constraints
- The hook must be implemented in TypeScript.
- The hook should be compatible with modern browsers that support
navigator.mediaDevices.getDisplayMedia(). - The
startSharingfunction should not start sharing immediately if permission hasn't been granted yet; it should request permission first. - The
stopSharingfunction should handle the case where the stream is null gracefully (no errors). - The hook should not introduce any unnecessary dependencies.
Notes
- Consider using
useEffectto manage the lifecycle of the screen share stream. - Pay close attention to error handling and provide informative error messages.
- Think about how to handle the case where the user closes the browser window while screen sharing is active. While not strictly required, a good solution would attempt to stop the stream on unmount.
- The
getDisplayMedia()function can accept options to control the screen share behavior (e.g., specifying which screens to show). For simplicity, you can assume default options for now. - Focus on the core functionality of requesting permission, starting/stopping the stream, and managing the state. UI rendering is the responsibility of the component using the hook.