Navigation

React Hooks

Code snippets for Custom Hooks that mostly used in my projects

Classic useLocalStorage

1
2import { useState, useEffect } from 'react';
3
4function useLocalStorage(key, initialValue) {
5  const isClient = typeof window === 'object';
6
7  const [storedValue, setStoredValue] = useState(() => {
8    if (!isClient) return initialValue;
9    try {
10      const item = window.localStorage.getItem(key);
11      return item ? JSON.parse(item) : initialValue;
12    } catch (error) {
13      console.warn(`Error reading localStorage key "${key}":`, error);
14      return initialValue;
15    }
16  });
17
18  useEffect(() => {
19    if (!isClient) return;
20    try {
21      window.localStorage.setItem(key, JSON.stringify(storedValue));
22    } catch (error) {
23      console.warn(`Error setting localStorage key "${key}":`, error);
24    }
25  }, [key, storedValue, isClient]);
26
27  return [storedValue, setStoredValue];
28}
29
30export default useLocalStorage;
31

useEncodeLocalStorage.ts

Please provide your own decodeBase64Unicode, encodeBase64Unicode

1import { decodeBase64Unicode, encodeBase64Unicode } from "@/lib/utils";
2import { useState, useEffect } from "react";
3
4/**
5 * A custom hook that syncs a state value to localStorage,
6 * **Base64-encoding** the JSON string in a Unicode-safe manner.
7 *
8 * @param key The key to store in localStorage
9 * @param initialValue The default value if none is in localStorage
10 * @returns [value, setValue]
11 */
12export function useEncodeLocalStorage<T>(
13    key: string,
14    initialValue: T
15): [T, React.Dispatch<React.SetStateAction<T>>] {
16    const [storedValue, setStoredValue] = useState<T>(() => {
17        try {
18            const item = localStorage.getItem(key);
19            if (item) {
20                // Decode base64 safely and parse JSON
21                const decoded = decodeBase64Unicode(item);
22                return JSON.parse(decoded) as T;
23            }
24        } catch (error) {
25            console.error(
26                "useEncodeLocalStorage: Error loading from localStorage",
27                error
28            );
29        }
30        return initialValue;
31    });
32
33    useEffect(() => {
34        try {
35            const json = JSON.stringify(storedValue);
36            const encoded = encodeBase64Unicode(json);
37            localStorage.setItem(key, encoded);
38        } catch (error) {
39            console.error(
40                "useEncodeLocalStorage: Error saving to localStorage",
41                error
42            );
43        }
44    }, [key, storedValue]);
45
46    return [storedValue, setStoredValue];
47}
48

useFetch.ts

1
2import { FetchError } from "./../data/types";
3import { useState, useCallback } from "react";
4
5interface FetchOptions extends RequestInit {
6    body?: any;
7}
8
9export interface UseFetchReturn<T> {
10    data: T | null;
11    setData: React.Dispatch<React.SetStateAction<T | null>>;
12    loading: boolean;
13    error: FetchError | null;
14    setError: React.Dispatch<React.SetStateAction<FetchError | null>>;
15    execute: (options?: FetchOptions) => Promise<void>;
16}
17
18const useFetch = <T = unknown>(
19    initialUrl: string,
20    initialOptions: FetchOptions = {}
21): UseFetchReturn<T> => {
22    const [url, setUrl] = useState<string>(initialUrl);
23    const [options, setOptions] = useState<FetchOptions>(initialOptions);
24    const [data, setData] = useState<T | null>(null);
25    const [loading, setLoading] = useState<boolean>(false);
26    const [error, setError] = useState<FetchError | null>(null);
27
28    const execute = useCallback(
29        async (overrideOptions?: FetchOptions) => {
30            setLoading(true);
31            setError(null);
32            try {
33                const response = await fetch(url, {
34                    ...options,
35                    ...overrideOptions
36                });
37
38                if (!response.ok) {
39                    const errorText = await response.text();
40                    throw new Error(
41                        JSON.stringify(
42                            {
43                                status: response.status,
44                                name: response.statusText,
45                                message: errorText
46                            },
47                            null,
48                            2
49                        )
50                    );
51                }
52
53                const responseData: T = await response.json();
54                setData(responseData);
55            } catch (err) {
56                const errJson = JSON.parse(err?.message || "{}");
57                console.log(errJson);
58                setError({
59                    status: errJson?.status || 500,
60                    name: errJson?.name || "Error",
61                    message: `${errJson?.message || "Unknown error"}`
62                });
63            } finally {
64                setLoading(false);
65            }
66        },
67        [url, options]
68    );
69
70    return { data, setData, loading, error, setError, execute };
71};
72
73export default useFetch;
74