Skip to content

Instantly share code, notes, and snippets.

@codingmatty
Created August 11, 2019 21:53
Show Gist options
  • Save codingmatty/87fa40f3618a1fc8638c74e89d52cb73 to your computer and use it in GitHub Desktop.
Save codingmatty/87fa40f3618a1fc8638c74e89d52cb73 to your computer and use it in GitHub Desktop.
import { useEffect, useState } from 'react';
/**
* Usage:
*
* const {response, error, loading} = useFetch({ url, ...options }, deps);
*/
export default function useFetch(
{
url,
method = 'GET',
body,
onFetchStart = () => {},
onFetchComplete = () => {},
onSuccess = () => {},
onFailure = () => {},
shouldFetch = method === 'GET',
json,
...miscFetchOptions
},
deps = []
) {
const [loading, setLoading] = useState(true); // Loading state true for SSR
const [response, setResponse] = useState();
const [error, setError] = useState();
// Wrap fetch in useEffect so it doesn't happen on SSR
const fetchData = async (data) => {
await onFetchStart();
setLoading(true);
setError();
try {
if (typeof json === 'string') {
body = JSON.stringify({ ...JSON.parse(json), ...data });
} else if (typeof json === 'object') {
body = JSON.stringify({ ...json, ...data });
}
const response = await fetch(url, {
...miscFetchOptions,
method,
headers: {
'Content-Type': json && 'application/json'
},
body
});
const contentType = response.headers.get('content-type') || '';
if (!contentType.includes('application/json')) {
if (response.status === 204) {
await onSuccess();
setResponse();
} else {
// This assumes the response should be JSON and textual response would mean an error
throw new Error(await response.text());
}
} else {
const responseJson = await response.json();
if (responseJson.errors) {
const jsonResponseError = new Error('JSON Error Response');
jsonResponseError.errors = responseJson.errors;
throw jsonResponseError;
} else {
await onSuccess(responseJson);
setResponse(responseJson);
}
}
} catch (error) {
await onFailure(error);
setError({
message: 'Fetch Error',
value: error.message,
error
});
} finally {
setLoading(false);
await onFetchComplete();
}
};
useEffect(
() => {
if (shouldFetch) {
fetchData();
}
},
// Run effect when url or options change.
[url, body, shouldFetch, ...deps]
);
return { response, error, loading, fetchData };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment