Custom React Hook: useNotification
This challenge asks you to create a custom React hook, useNotification, designed to manage and display user notifications within a React application. A robust notification system is crucial for providing feedback to users about important events, errors, or successful actions, enhancing the overall user experience.
Problem Description
Your task is to implement a useNotification hook in TypeScript that provides a simple and declarative way to manage notification state and display logic. The hook should allow components to trigger notifications, specify their type (e.g., 'info', 'success', 'warning', 'error'), and automatically handle their visibility and removal.
Key Requirements:
- State Management: The hook must manage the current notification's state, including its message, type, and visibility.
- Triggering Notifications: Provide a function to trigger a new notification. This function should accept the notification message and its type.
- Automatic Dismissal: Notifications should automatically dismiss after a configurable duration.
- Unique Notifications: The hook should only display one notification at a time. If a new notification is triggered while another is active, the new one should replace the old one.
- TypeScript Support: The hook and its related types should be written in TypeScript for type safety.
Expected Behavior:
- When a notification is triggered using the provided function, it should become visible.
- The notification should display the provided message and be styled according to its type (though styling itself is outside the scope of this hook, the type information should be available).
- After a set timeout, the notification should automatically disappear.
- If a new notification is triggered before the timeout of the previous one, the previous notification should be dismissed immediately, and the new one should appear.
Edge Cases:
- What happens if the timeout duration is set to zero or a negative number? (The hook should ideally handle this gracefully, perhaps by not dismissing automatically).
- What if no notification is active? The hook should return default or empty values for notification properties.
Examples
Example 1: Basic Notification
// In a parent component
import React from 'react';
import { useNotification } from './useNotification'; // Assuming your hook is in this file
function App() {
const { notification, triggerNotification } = useNotification({ autoDismissDuration: 3000 });
const handleClick = () => {
triggerNotification('Operation completed successfully!', 'success');
};
return (
<div>
<button onClick={handleClick}>Show Success Notification</button>
{notification && (
<div style={{ border: '1px solid green', padding: '10px', marginTop: '10px' }}>
<p>{notification.message}</p>
<small>{notification.type}</small>
</div>
)}
</div>
);
}
Input to useNotification hook: { autoDismissDuration: 3000 }
Input to triggerNotification function: 'Operation completed successfully!', 'success'
Expected Output (rendered in the UI):
A green bordered div appears displaying:
Operation completed successfully!
success
This div will disappear after 3 seconds.
Example 2: Error Notification Replacing Info
// In a parent component
import React from 'react';
import { useNotification } from './useNotification';
function AnotherComponent() {
const { notification, triggerNotification } = useNotification({ autoDismissDuration: 5000 });
const showInfo = () => {
triggerNotification('Loading data...', 'info');
};
const showError = () => {
triggerNotification('Failed to load data!', 'error');
};
return (
<div>
<button onClick={showInfo}>Show Info</button>
<button onClick={showError}>Show Error</button>
{notification && (
<div style={{ border: `1px solid ${notification.type === 'error' ? 'red' : 'blue'}`, padding: '10px', marginTop: '10px' }}>
<p>{notification.message}</p>
<small>{notification.type}</small>
</div>
)}
</div>
);
}
Scenario:
- User clicks "Show Info".
triggerNotification('Loading data...', 'info')is called. - An info notification appears.
- While the info notification is still visible, the user clicks "Show Error".
triggerNotification('Failed to load data!', 'error')is called.
Expected Output (rendered in the UI): Initially, a blue bordered div with "Loading data..." appears. Then, it is immediately replaced by a red bordered div with "Failed to load data!". The error notification will dismiss after 5 seconds.
Example 3: No Auto-Dismissal
// In a parent component
import React from 'react';
import { useNotification } from './useNotification';
function ManualDismissComponent() {
// Set autoDismissDuration to 0 for no auto-dismissal
const { notification, triggerNotification } = useNotification({ autoDismissDuration: 0 });
const showWarning = () => {
triggerNotification('Please review your settings.', 'warning');
};
const dismiss = () => {
// Assuming a dismissNotification function will be added to the hook later
// For now, this is conceptual. The hook should return a way to clear.
// Let's refine the hook to return a clear function.
};
return (
<div>
<button onClick={showWarning}>Show Persistent Warning</button>
{notification && (
<div style={{ border: '1px solid orange', padding: '10px', marginTop: '10px' }}>
<p>{notification.message}</p>
<small>{notification.type}</small>
{/* If a clear function is provided by the hook: */}
{/* <button onClick={dismiss}>Dismiss</button> */}
</div>
)}
</div>
);
}
Input to useNotification hook: { autoDismissDuration: 0 }
Input to triggerNotification function: 'Please review your settings.', 'warning'
Expected Output (rendered in the UI): An orange bordered div appears with "Please review your settings." and it does not disappear automatically. (A mechanism to manually dismiss would be a good enhancement, but for this challenge, focus on the auto-dismiss behavior).
Constraints
- The
useNotificationhook should accept an optional configuration object forautoDismissDuration(in milliseconds). If not provided, a reasonable default (e.g., 5000ms) should be used. - The
triggerNotificationfunction should accept amessage(string) and atype(string, expected to be one of 'info', 'success', 'warning', 'error'). - The hook should return an object containing the current
notificationstate and thetriggerNotificationfunction. - The
notificationstate object should have properties likemessage(string),type(string), and potentiallyisVisible(boolean), thoughisVisiblecan be implicitly handled by the presence ofmessageandtype. - The solution should be implemented in TypeScript.
Notes
- Consider using
setTimeoutandclearTimeoutwithin your hook to manage the auto-dismissal. - Think about the types for the notification object and the hook's return value.
- While styling is not part of this challenge, the
typeproperty is provided so that consuming components can apply appropriate styles. - Consider adding a
clearNotificationfunction to the hook's return value for manual dismissal, especially for cases whereautoDismissDurationmight be 0.