Skip to content

Instantly share code, notes, and snippets.

@jasonsbarr
Last active December 13, 2021 17:08
Show Gist options
  • Select an option

  • Save jasonsbarr/84c39c83070ced72ad11b69661fdfbed to your computer and use it in GitHub Desktop.

Select an option

Save jasonsbarr/84c39c83070ced72ad11b69661fdfbed to your computer and use it in GitHub Desktop.
React hook to render data from a GET request using `fetch` based on states of a Promise lifecycle
import { useFetchGet } from "../hooks";
import ResolvedComponent from "./";
/**
* Example use case
* @see [Use in an actual project]{@link https://github.com/jasonsbarr/Sprint-Challenge-Single-Page-Apps/blob/d379e83f5d2bb77566d5fd37bbf2d5812438417d/src/pages/Characters.js|Github}
*/
const Component = () => {
const render = useFetchGet(url);
return render({
initial: () => <div>Haven't fetched yet!</div>
pending: () => <div>Loading...</div>,
error: err => <div>Error: {err.message}</div>,
data: data => <ResolvedComponent data={data} />,
});
};
/**
* Matches current state of a Promise lifecycle and returns
* Object of partially applied functions to render data.
*
* @param {Object} state
* @param {Object} match
* @returns {Object}
*/
const matchAsyncStates = state => match =>
state.initial ? match.initial()
: state.pending ? match.pending()
: state.error ? match.error(state.error)
: state.data ? match.data(state.data)
: null;
import { useState, useEffect } from "react";
import { matchAsyncStates as render } from "./utils";
/**
* React hook for conditional rendering based on Promise life-
* cycle states for simple GET operations using fetch().
*
* @param {String} url - The URL to run the query on
* @param {Object} args - Set of args passed to function
* @param {Boolean} [args.initialPersist=false] - whether initial state should be rendered while Promise is pending
* @param {String} [args.method="json"] - response object method
* @returns {Function}
*/
export const useFetchGet = (
url,
{ initialPersist = false, method = "json" } = {},
) => {
const [initial, setInitial] = useState(true);
const [pending, setPending] = useState(false);
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
setInitial(initialPersist);
setPending(true);
fetch(url)
.then(response => {
return !response.ok
? new Error(response.statusText)
: response;
})
.then(response => response[method]())
.then(data => {
setInitial(false);
setPending(false);
setError(null);
setData(data);
})
.catch(error => {
setInitial(false);
setPending(false);
setError(error);
setData(null);
});
}, [initialPersist, method, url]);
return render({ initial, pending, error, data });
};
export default useFetchGet;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment