Implement usePageLeave React Hook
Create a custom React hook, usePageLeave, that triggers a callback function when the user navigates away from the current browser page. This is useful for scenarios like saving unsaved form data, displaying a confirmation message before leaving, or tracking user exit behavior.
Problem Description
Your task is to implement a React hook named usePageLeave that accepts a single argument: a callback function. This callback function should be executed precisely when the user attempts to navigate away from the current web page.
Key Requirements:
- Callback Execution: The provided callback function must be invoked when a "page leave" event occurs.
- Cleanup: Ensure that event listeners are properly removed when the component using the hook unmounts to prevent memory leaks.
- Reusability: The hook should be generic and usable across different components.
Expected Behavior:
When the user performs an action that navigates them away from the current page (e.g., clicking a link to an external site, closing the tab/window, hitting the back button), the callback function passed to usePageLeave should be executed.
Edge Cases to Consider:
- Multiple
usePageLeaveinstances: How does the hook behave if used in multiple components simultaneously? - Dynamic callback function: What happens if the callback function passed to the hook changes between renders?
- Unmounting: Ensure no errors or memory leaks occur when the component using the hook unmounts.
Examples
Example 1:
import React from 'react';
import { usePageLeave } from './usePageLeave'; // Assuming your hook is in this file
function MyComponent() {
const handlePageLeave = () => {
console.log('User is leaving the page!');
// Potentially save data or show a confirmation
};
usePageLeave(handlePageLeave);
return <div>Content of my page. Try to navigate away!</div>;
}
Output:
When the user navigates away from MyComponent (e.g., closes the tab, clicks a link to a different URL), the following will be logged to the console:
User is leaving the page!
Explanation:
The usePageLeave hook attaches an event listener that monitors for page leave events. When such an event is detected, the handlePageLeave function provided to the hook is executed.
Example 2:
import React, { useState, useCallback } from 'react';
import { usePageLeave } from './usePageLeave';
function FormComponent() {
const [formData, setFormData] = useState({ name: '', email: '' });
const [isDirty, setIsDirty] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
setIsDirty(true);
};
const handlePageLeave = useCallback(() => {
if (isDirty) {
alert('You have unsaved changes! Are you sure you want to leave?');
// In a real app, you might trigger a save or show a modal
}
}, [isDirty]); // Dependency on isDirty
usePageLeave(handlePageLeave);
return (
<div>
<h2>Unsaved Form</h2>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
placeholder="Name"
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
/>
{isDirty && <p>Unsaved changes!</p>}
</div>
);
}
Output:
If the user types into the form fields (isDirty becomes true) and then attempts to navigate away, an alert box will appear:
You have unsaved changes! Are you sure you want to leave?
If the user navigates away without changing any form fields (isDirty remains false), no alert will appear.
Explanation:
The usePageLeave hook, in conjunction with useState and useCallback, allows for conditional execution of the leave handler. The callback is memoized using useCallback to ensure it's stable and only re-creates if isDirty changes. This prevents unnecessary re-registrations of the event listener and ensures the most up-to-date isDirty state is checked.
Constraints
- The hook must be implemented in TypeScript.
- The hook should utilize React's
useEffecthook for managing side effects and cleanup. - Avoid using
window.onbeforeunloaddirectly in the component; encapsulate this logic within the hook. - The callback function should be treated as a potentially changing value, meaning the hook should adapt if the callback reference changes.
Notes
Consider what browser events are most appropriate for detecting a "page leave" action. Think about how to handle the navigator.sendBeacon API or the beforeunload event for more robust handling of unsaved data. The primary event to focus on for this challenge is beforeunload.