Code snippets for Custom Hooks that mostly used in my projects
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
const isClient = typeof window === 'object';
const [storedValue, setStoredValue] = useState(() => {
if (!isClient) return initialValue;
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.warn(`Error reading localStorage key "${key}":`, error);
return initialValue;
}
});
useEffect(() => {
if (!isClient) return;
try {
window.localStorage.setItem(key, JSON.stringify(storedValue));
} catch (error) {
console.warn(`Error setting localStorage key "${key}":`, error);
}
}, [key, storedValue, isClient]);
return [storedValue, setStoredValue];
}
export default useLocalStorage;
Please provide your own decodeBase64Unicode, encodeBase64Unicode
import { decodeBase64Unicode, encodeBase64Unicode } from "@/lib/utils";
import { useState, useEffect } from "react";
/**
* A custom hook that syncs a state value to localStorage,
* **Base64-encoding** the JSON string in a Unicode-safe manner.
*
* @param key The key to store in localStorage
* @param initialValue The default value if none is in localStorage
* @returns [value, setValue]
*/
export function useEncodeLocalStorage<T>(
key: string,
initialValue: T
): [T, React.Dispatch<React.SetStateAction<T>>] {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = localStorage.getItem(key);
if (item) {
// Decode base64 safely and parse JSON
const decoded = decodeBase64Unicode(item);
return JSON.parse(decoded) as T;
}
} catch (error) {
console.error(
"useEncodeLocalStorage: Error loading from localStorage",
error
);
}
return initialValue;
});
useEffect(() => {
try {
const json = JSON.stringify(storedValue);
const encoded = encodeBase64Unicode(json);
localStorage.setItem(key, encoded);
} catch (error) {
console.error(
"useEncodeLocalStorage: Error saving to localStorage",
error
);
}
}, [key, storedValue]);
return [storedValue, setStoredValue];
}
import { FetchError } from "./../data/types";
import { useState, useCallback } from "react";
interface FetchOptions extends RequestInit {
body?: any;
}
export interface UseFetchReturn<T> {
data: T | null;
setData: React.Dispatch<React.SetStateAction<T | null>>;
loading: boolean;
error: FetchError | null;
setError: React.Dispatch<React.SetStateAction<FetchError | null>>;
execute: (options?: FetchOptions) => Promise<void>;
}
const useFetch = <T = unknown>(
initialUrl: string,
initialOptions: FetchOptions = {}
): UseFetchReturn<T> => {
const [url, setUrl] = useState<string>(initialUrl);
const [options, setOptions] = useState<FetchOptions>(initialOptions);
const [data, setData] = useState<T | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<FetchError | null>(null);
const execute = useCallback(
async (overrideOptions?: FetchOptions) => {
setLoading(true);
setError(null);
try {
const response = await fetch(url, {
...options,
...overrideOptions
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(
JSON.stringify(
{
status: response.status,
name: response.statusText,
message: errorText
},
null,
2
)
);
}
const responseData: T = await response.json();
setData(responseData);
} catch (err) {
const errJson = JSON.parse(err?.message || "{}");
console.log(errJson);
setError({
status: errJson?.status || 500,
name: errJson?.name || "Error",
message: `${errJson?.message || "Unknown error"}`
});
} finally {
setLoading(false);
}
},
[url, options]
);
return { data, setData, loading, error, setError, execute };
};
export default useFetch;