typecode
ReactCustom Hooks/hooks.ts
1import { useState, useEffect, useRef, useCallback } from "react"
2
3interface FetchState<T> {
4 data: T | null
5 loading: boolean
6 error: string | null
7}
8
9export function useFetch<T>(url: string): FetchState<T> {
10 const [state, setState] = useState<FetchState<T>>({
11 data: null,
12 loading: true,
13 error: null,
14 })
15
16 useEffect(() => {
17 const controller = new AbortController()
18 setState((prev) => ({ ...prev, loading: true, error: null }))
19
20 fetch(url, { signal: controller.signal })
21 .then((res) => {
22 if (!res.ok) throw new Error(res.statusText)
23 return res.json()
24 })
25 .then((data) => setState({ data, loading: false, error: null }))
26 .catch((err) => {
27 if (err.name !== "AbortError") {
28 setState({ data: null, loading: false, error: err.message })
29 }
30 })
31
32 return () => controller.abort()
33 }, [url])
34
35 return state
36}
37
38export function useDebounce<T>(value: T, delay: number): T {
39 const [debouncedValue, setDebouncedValue] = useState(value)
40
41 useEffect(() => {
42 const timer = setTimeout(() => setDebouncedValue(value), delay)
43 return () => clearTimeout(timer)
44 }, [value, delay])
45
46 return debouncedValue
47}
48
49export function useLocalStorage<T>(key: string, initialValue: T) {
50 const [storedValue, setStoredValue] = useState<T>(() => {
51 try {
52 const item = window.localStorage.getItem(key)
53 return item ? JSON.parse(item) : initialValue
54 } catch {
55 return initialValue
56 }
57 })
58
59 const setValue = useCallback(
60 (value: T | ((prev: T) => T)) => {
61 const valueToStore =
62 value instanceof Function ? value(storedValue) : value
63 setStoredValue(valueToStore)
64 window.localStorage.setItem(key, JSON.stringify(valueToStore))
65 },
66 [key, storedValue]
67 )
68
69 return [storedValue, setValue] as const
70}
71
72export function usePrevious<T>(value: T): T | undefined {
73 const ref = useRef<T | undefined>(undefined)
74
75 useEffect(() => {
76 ref.current = value
77 }, [value])
78
79 return ref.current
80}
81
82export function useInterval(callback: () => void, delay: number | null) {
83 const savedCallback = useRef(callback)
84
85 useEffect(() => {
86 savedCallback.current = callback
87 }, [callback])
88
89 useEffect(() => {
90 if (delay === null) return
91 const id = setInterval(() => savedCallback.current(), delay)
92 return () => clearInterval(id)
93 }, [delay])
94}
0WPM
100%Accuracy
00:00Time
0%
Progress