Poor mans React Query / SWR

· Bj√∂rn-Eric's Developer notes

A request state wrapper around fetch
#react, #typescript, #utils

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>

Home