hooks.ts 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { useState, useEffect, useCallback } from 'react';
  2. /**
  3. * Custom hook for persisting form state to localStorage
  4. * @param key - Unique key for localStorage
  5. * @param initialValue - Initial value for the state
  6. * @returns [state, setState, clearState] tuple
  7. */
  8. export function useLocalStorage<T>(
  9. key: string,
  10. initialValue: T
  11. ): [T, (value: T | ((prevValue: T) => T)) => void, () => void] {
  12. // Always start with initialValue to prevent hydration mismatch
  13. // Load from localStorage only after client-side hydration
  14. const [storedValue, setStoredValue] = useState<T>(initialValue);
  15. // Load value from localStorage after component mounts (client-side only)
  16. useEffect(() => {
  17. try {
  18. const item = window.localStorage.getItem(key);
  19. if (item) {
  20. setStoredValue(JSON.parse(item));
  21. }
  22. } catch (error) {
  23. console.warn(`Error loading localStorage key "${key}":`, error);
  24. }
  25. }, [key]);
  26. // Return a wrapped version of useState's setter function that ...
  27. // ... persists the new value to localStorage.
  28. const setValue = useCallback(
  29. (value: T | ((prevValue: T) => T)) => {
  30. try {
  31. // Allow value to be a function so we have same API as useState
  32. const valueToStore =
  33. value instanceof Function ? value(storedValue) : value;
  34. // Save state
  35. setStoredValue(valueToStore);
  36. // Save to local storage
  37. if (typeof window !== 'undefined') {
  38. window.localStorage.setItem(key, JSON.stringify(valueToStore));
  39. }
  40. } catch (error) {
  41. // A more advanced implementation would handle the error case
  42. console.error(`Error saving localStorage key "${key}":`, error);
  43. }
  44. },
  45. [key, storedValue]
  46. );
  47. // Function to clear the stored value
  48. const clearValue = useCallback(() => {
  49. try {
  50. setStoredValue(initialValue);
  51. if (typeof window !== 'undefined') {
  52. window.localStorage.removeItem(key);
  53. }
  54. } catch (error) {
  55. console.error(`Error clearing localStorage key "${key}":`, error);
  56. }
  57. }, [key, initialValue]);
  58. return [storedValue, setValue, clearValue];
  59. }
  60. /**
  61. * Hook for auto-saving form state with debouncing
  62. * @param key - Unique key for localStorage
  63. * @param value - Current form value
  64. * @param delay - Debounce delay in milliseconds (default: 500ms)
  65. */
  66. export function useAutoSave<T>(key: string, value: T, delay = 500) {
  67. useEffect(() => {
  68. const timeoutId = setTimeout(() => {
  69. if (typeof window !== 'undefined') {
  70. try {
  71. window.localStorage.setItem(key, JSON.stringify(value));
  72. } catch (error) {
  73. console.error(`Error auto-saving localStorage key "${key}":`, error);
  74. }
  75. }
  76. }, delay);
  77. return () => clearTimeout(timeoutId);
  78. }, [key, value, delay]);
  79. }