Implementing a useContrastMode Hook for Dynamic Theme Switching in React
This challenge focuses on creating a reusable React hook, useContrastMode, that manages and provides a state variable for toggling between a light and dark contrast mode. This hook will be useful for building applications with user-configurable themes, enhancing accessibility and user experience. The hook should persist the user's preference across re-renders and potentially across page refreshes (though persistence is not a core requirement for this challenge).
Problem Description
You are tasked with implementing the useContrastMode hook in TypeScript. This hook should:
- Initialize State: Start with a default contrast mode (either 'light' or 'dark' - you can choose the default).
- Toggle Mode: Provide a function to toggle between 'light' and 'dark' contrast modes.
- Return Values: Return an array containing:
- The current contrast mode string ('light' or 'dark').
- A function to toggle the contrast mode.
- Persistence (Optional): Ideally, the hook should attempt to persist the contrast mode preference using
localStorage. IflocalStorageis unavailable (e.g., in a server-side rendering environment), it should gracefully fall back to only managing the state in memory. - Update on Change: When the contrast mode is toggled, the hook should update
localStorage(if available) to persist the new preference.
Expected Behavior:
- On initial mount, the hook should check
localStoragefor a saved contrast mode. If found, it should initialize the state with that value. Otherwise, it should use the default. - Toggling the mode should update the state and, if available,
localStorage. - Subsequent mounts should retrieve the saved contrast mode from
localStorage(if present) and initialize the state accordingly.
Examples
Example 1:
Input: Initial state is 'light', localStorage is empty.
Output: ['light', toggleContrastMode]
Explanation: The hook initializes with 'light' because it's the default and localStorage is empty. `toggleContrastMode` is a function that, when called, will change the state to 'dark' and update localStorage.
Example 2:
Input: Initial state is 'light', localStorage contains 'dark'.
Output: ['dark', toggleContrastMode]
Explanation: The hook initializes with 'dark' because it finds 'dark' in localStorage. `toggleContrastMode` is a function that, when called, will change the state to 'light' and update localStorage.
Example 3: (Edge Case - localStorage unavailable)
Input: Initial state is 'light', localStorage is unavailable (e.g., server-side rendering).
Output: ['light', toggleContrastMode]
Explanation: The hook initializes with 'light' as the default. `toggleContrastMode` will update the state in memory, but will *not* attempt to update localStorage.
Constraints
- The hook must be written in TypeScript.
- The contrast mode state must be strictly either 'light' or 'dark'.
- The hook should handle the case where
localStorageis not available gracefully (without throwing errors). - The hook should be reusable in any React component.
- The
toggleContrastModefunction should be a stable function reference (i.e., it shouldn't change on every render).
Notes
- Consider using
useStateto manage the contrast mode state. - Use
localStorage.getItemandlocalStorage.setItemto interact withlocalStorage. - You can use a try-catch block to handle potential errors when accessing
localStorage. - Think about how to handle the initial state when
localStorageis unavailable. - Focus on creating a clean, well-documented, and reusable hook. Error handling for
localStorageis important, but the core functionality is the state management and toggling.