React Hook: usePreferredLanguage for User Language Preference
This challenge asks you to create a custom React hook, usePreferredLanguage, that manages and provides the user's preferred language setting. The hook should persist the language preference in local storage, allowing the application to remember the user's choice across sessions. This is a common requirement for internationalized applications, providing a smoother user experience.
Problem Description
You need to implement the usePreferredLanguage hook in TypeScript. This hook should:
- Initialize: On initial mount, check local storage for a stored language preference. If found, use it; otherwise, default to 'en' (English).
- Provide Current Language: Expose the current preferred language as a string via the
languageproperty. - Provide Setter Function: Expose a function
setPreferredLanguagethat allows components to update the preferred language. This function should:- Update the internal state of the hook, triggering a re-render.
- Save the new language preference to local storage under the key 'preferredLanguage'.
- Handle Invalid Input: The
setPreferredLanguagefunction should gracefully handle invalid language codes (e.g., non-string values, unexpected strings) by logging an error and not updating the state or local storage. It should default to 'en' in such cases.
Expected Behavior:
- The hook should return an object with two properties:
language(string) andsetPreferredLanguage(function). - The
languageproperty should reflect the current preferred language. - Calling
setPreferredLanguagewith a valid language code should update thelanguageproperty and save the preference to local storage. - Calling
setPreferredLanguagewith an invalid language code should log an error and leave thelanguageproperty unchanged. - Subsequent mounts of components using the hook should retrieve the language from local storage if it exists.
Examples
Example 1:
Input: Initial local storage is empty.
Output: { language: 'en', setPreferredLanguage: (language: string) => void }
Explanation: The hook initializes with the default language 'en' because local storage is empty.
Example 2:
Input: Local storage contains { preferredLanguage: 'es' }.
Output: { language: 'es', setPreferredLanguage: (language: string) => void }
Explanation: The hook retrieves 'es' from local storage and sets the initial language to 'es'.
Example 3:
Input: Component calls setPreferredLanguage('fr');
Output: { language: 'fr', setPreferredLanguage: (language: string) => void } (after state update)
Local Storage: { preferredLanguage: 'fr' }
Explanation: The language is updated to 'fr', and local storage is updated accordingly.
Example 4:
Input: Component calls setPreferredLanguage(123);
Output: { language: 'en', setPreferredLanguage: (language: string) => void } (after state update and error logging)
Local Storage: { preferredLanguage: 'en' }
Explanation: The input is invalid. An error is logged, the language defaults to 'en', and local storage is updated.
Constraints
- The language code should be a string.
- Local storage keys must be strings.
- The hook should be performant; avoid unnecessary re-renders.
- The hook should be compatible with functional React components.
- The hook should handle potential errors when accessing local storage (though for simplicity, assume local storage is available).
Notes
- Consider using
useStateto manage the internal state of the hook. - Use
localStorage.getItemandlocalStorage.setItemto interact with local storage. - Think about how to handle potential errors when parsing data from local storage.
- Error logging can be done using
console.error. - The hook should be reusable across different components in your application.
- Focus on clean, readable, and well-documented code.