Sometimes you don't want to, or can't add a (another) dependency and just want to send of a request and know how it went.
1// useFetcher.ts
2export function useFetcher<T>(url: string): { isLoading: boolean, error: any, data: T | undefined } {
3 const [data, setData] = useState(undefined);
4 const [isLoading, setIsLoading] = useState(false);
5 const [error, setError] = useState(false);
6
7 const get = async () => {
8 setIsLoading(true);
9
10 fetch(url)
11 .then((resp) => resp.json())
12 .then(data => setData(data))
13 .catch(error => setError(error))
14 .finally(() => setIsLoading(false))
15 }
16
17 useEffect(() => {
18 get()
19 }, [])
20
21
22 return {
23 data,
24 isLoading,
25 error,
26 };
27}
And use it something like this:
1type Todo = {
2 userId: number
3 id: number
4 title: string
5 completed: boolean
6}
7
8const todos = useFetcher<Todo[]>(
9 'https://jsonplaceholder.typicode.com/todos',
10)
11
12if (todos.isLoading) return <div>Loading...</div>
13if (todos.error) return <div>Error: {error.message}</div>
14
15return (
16 <ul>
17 {todos.data?.map((todo) => (
18 <li key={todo.id}>{todo.title}</li>
19 ))}
20 </ul>
21)
By not destructuring todos
we can use useFetcher
as many times as we want, on multiple URLs. If you are only going to fetch once this might look cleaner:
1const { isLoading, error, data } = useFetcher<Todo[]>(
2 'https://jsonplaceholder.typicode.com/todos',
3)
4/* ... */
5
6if (isLoading) return <div>Loading...</div>
7if (error) return <div>Error: {error.message}</div>