Skip to content

Instantly share code, notes, and snippets.

@dzenand
Last active August 21, 2023 08:14
Show Gist options
  • Save dzenand/b38b36d3c87e29420a59062cd3c2a487 to your computer and use it in GitHub Desktop.
Save dzenand/b38b36d3c87e29420a59062cd3c2a487 to your computer and use it in GitHub Desktop.
A custom hook that wraps around the fetch API to make HTTP requests
import { startTransition, useCallback, useState } from "react";
interface HttpError {
status: number;
message: string;
}
type RequestBody = BodyInit | Record<string, unknown>;
/// <summary>
/// A custom hook that wraps around the fetch API to make HTTP requests.
/// </summary>
/// <example>
/// const { data, error, isLoading, mutate } = useHttpMutation<{ id: string }>(url, { method: "POST" });
/// </example>
export function useHttpMutation<T>(url: RequestInfo | URL, initialInit?: RequestInit) {
const [state, setState] = useState<{ data: T | null; error: HttpError | null; isLoading: boolean }>({
data: null,
error: null,
isLoading: false
});
const mutate = useCallback(
async (body?: RequestBody): Promise<{ data: T | null; error: HttpError | null }> => {
setState({ isLoading: true, data: null, error: null });
try {
const response = await fetch(url, {
headers: {
"Content-Type": "application/json;charset=utf-8"
},
body: body ? JSON.stringify(body) : null,
...initialInit
});
if (!response.ok) {
const httpError: HttpError = {
status: response.status,
message: response.statusText
};
startTransition(() => {
setState({ isLoading: false, data: null, error: httpError });
});
return { data: null, error: httpError };
}
const data = await response.text();
const responseData: T = data.length > 0 ? JSON.parse(data) : null;
startTransition(() => {
setState({ isLoading: false, data: responseData, error: null });
});
return { data: responseData, error: null };
} catch (err) {
startTransition(() => {
setState({ isLoading: false, data: null, error: err as HttpError });
});
return { data: null, error: err as HttpError };
}
},
[initialInit, url]
);
return {
get data() {
return state.data;
},
get error() {
return state.error;
},
get isLoading() {
return state.isLoading;
},
mutate
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment