Custom Hooks in React
Key Concepts
- useLocalStorage: Manages state that persists in local storage.
- useFetch: Fetches data from an API and manages loading and error states.
- useToggle: Manages a boolean state and provides a toggle function.
- useDebounce: Delays the execution of a function until after a specified time has elapsed.
- usePrevious: Tracks the previous value of a state or prop.
useLocalStorage
The useLocalStorage
custom hook allows you to manage state that persists in the browser's local storage. This is useful for storing user preferences or other data that should survive page reloads.
Example:
import { useState, useEffect } from 'react'; function useLocalStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { return initialValue; } }); const setValue = (value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.log(error); } }; return [storedValue, setValue]; } function App() { const [name, setName] = useLocalStorage('name', 'John'); return ( <div> <input type="text" placeholder="Enter your name" value={name} onChange={(e) => setName(e.target.value)} /> <p>Hello, {name}!</p> </div> ); }
useFetch
The useFetch
custom hook fetches data from an API and manages the loading and error states. This hook is useful for simplifying data fetching logic in your components.
Example:
import { useState, useEffect } from 'react'; function useFetch(url) { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { async function fetchData() { try { const response = await fetch(url); const json = await response.json(); setData(json); } catch (error) { setError(error); } finally { setLoading(false); } } fetchData(); }, [url]); return { data, loading, error }; } function App() { const { data, loading, error } = useFetch('https://api.example.com/data'); if (loading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>; return ( <div> <h1>Data:</h1> <pre>{JSON.stringify(data, null, 2)}</pre> </div> ); }
useToggle
The useToggle
custom hook manages a boolean state and provides a toggle function. This is useful for managing simple on/off states like showing/hiding a modal or toggling a menu.
Example:
import { useState } from 'react'; function useToggle(initialValue = false) { const [value, setValue] = useState(initialValue); const toggle = () => { setValue(!value); }; return [value, toggle]; } function App() { const [isOn, toggleIsOn] = useToggle(false); return ( <div> <p>The switch is {isOn ? 'ON' : 'OFF'}</p> <button onClick={toggleIsOn}>Toggle</button> </div> ); }
useDebounce
The useDebounce
custom hook delays the execution of a function until after a specified time has elapsed since the last time the function was invoked. This is useful for debouncing search inputs or other events that trigger frequent updates.
Example:
import { useState, useEffect } from 'react'; function useDebounce(value, delay) { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(value); }, delay); return () => { clearTimeout(handler); }; }, [value, delay]); return debouncedValue; } function App() { const [query, setQuery] = useState(''); const debouncedQuery = useDebounce(query, 500); useEffect(() => { if (debouncedQuery) { // Perform search or other action with debouncedQuery } }, [debouncedQuery]); return ( <div> <input type="text" placeholder="Search..." value={query} onChange={(e) => setQuery(e.target.value)} /> <p>Searching for: {debouncedQuery}</p> </div> ); }
usePrevious
The usePrevious
custom hook tracks the previous value of a state or prop. This is useful for comparing the current value with the previous value, such as detecting changes in a form input or a prop value.
Example:
import { useRef, useEffect } from 'react'; function usePrevious(value) { const ref = useRef(); useEffect(() => { ref.current = value; }, [value]); return ref.current; } function App() { const [count, setCount] = useState(0); const previousCount = usePrevious(count); return ( <div> <p>Current count: {count}</p> <p>Previous count: {previousCount}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }
Analogies
useLocalStorage: Think of a sticky note on your computer screen. The note (state) stays there even if you close and reopen the computer (page reloads).
useFetch: Imagine a chef who orders ingredients (data) from a store (API). The chef (component) waits (loading state) and handles any issues (error state) until the ingredients arrive.
useToggle: Consider a light switch. The switch (state) can be either on or off, and flipping the switch (toggle function) changes its state.
useDebounce: Picture a person who only speaks after pausing for a moment. The person (function) waits (debounce) before saying something, ensuring they don't speak too quickly.
usePrevious: Think of a camera that takes a picture of a scene (state) before it changes. The camera (hook) captures the previous scene (value) for comparison.