Hone logo
Hone
Problems

Implementing a usePageLeave Hook in React

The usePageLeave hook allows you to trigger a specific function when a user navigates away from a React component. This is useful for prompting users to save unsaved changes, confirming they want to leave, or performing any cleanup tasks before the component unmounts. This challenge asks you to implement this hook from scratch.

Problem Description

You need to create a custom React hook called usePageLeave. This hook accepts a callback function as an argument. When the user attempts to leave the page (e.g., by clicking a link, pressing the back button, or closing the tab), the browser's beforeunload event will fire. Your hook should listen for this event and execute the provided callback function. The callback function should receive a single argument: an event object.

Key Requirements:

  • Event Listener: The hook must attach a beforeunload event listener to the window object.
  • Callback Execution: The callback function provided to the hook must be executed when the beforeunload event fires.
  • Cleanup: The hook must remove the event listener when the component unmounts to prevent memory leaks.
  • Type Safety: The hook should be written in TypeScript and properly typed.
  • Return Value: The hook should not return anything.

Expected Behavior:

When the component using usePageLeave is mounted, the beforeunload event listener is attached. When the user attempts to leave the page, the callback function is executed. When the component is unmounted, the event listener is removed.

Edge Cases to Consider:

  • Multiple Calls: What happens if the hook is called multiple times within the same component? Each call should register its own event listener and callback.
  • Unmounting Before Navigation: The component might unmount before the user actually leaves the page. The event listener should still be removed.
  • Callback with No Arguments: The callback function might not expect any arguments. The hook should still pass the event object.

Examples

Example 1:

Input: A component using usePageLeave with a callback that displays a confirmation dialog.
Output: When the user attempts to leave the page, a confirmation dialog appears prompting them to save their changes.
Explanation: The usePageLeave hook registers the beforeunload event and executes the callback, which triggers the dialog.

Example 2:

Input: A component using usePageLeave with a callback that logs a message to the console.
Output: When the user attempts to leave the page, the message "User is leaving!" is logged to the console.
Explanation: The usePageLeave hook registers the beforeunload event and executes the callback, which logs the message.

Example 3: (Edge Case)

Input: A component mounts, calls usePageLeave, unmounts before the user navigates away.
Output: No confirmation dialog appears, and no error is thrown.
Explanation: The usePageLeave hook correctly removes the event listener during unmount, preventing unexpected behavior.

Constraints

  • The hook must be implemented using functional components and hooks in React.
  • The hook must be written in TypeScript.
  • The callback function passed to the hook must be a function.
  • The hook should not introduce any unnecessary dependencies.
  • The hook should be performant and avoid blocking the main thread.

Notes

  • The beforeunload event can only be reliably used to display a confirmation dialog to the user. Attempting to perform complex operations within the callback is generally discouraged as it can lead to unpredictable behavior.
  • Consider how to handle multiple calls to the hook within the same component. Each call should register its own listener.
  • The event object passed to the callback contains information about the event, but accessing it directly can be unreliable. Focus on using it to trigger a confirmation dialog or perform simple cleanup tasks.
  • Remember to clean up the event listener when the component unmounts to prevent memory leaks. The useEffect hook with a cleanup function is a good approach.
Loading editor...
typescript