Skip to content

Instantly share code, notes, and snippets.

@DanCouper
Last active July 25, 2019 23:15
Show Gist options
  • Select an option

  • Save DanCouper/3473f0414cc398e0d6b7ffa29eccf5e9 to your computer and use it in GitHub Desktop.

Select an option

Save DanCouper/3473f0414cc398e0d6b7ffa29eccf5e9 to your computer and use it in GitHub Desktop.
useRestAPI
import React from "react";
// ex. API.get(path: string, opts:any = {}):Promise
import API from "./rest-api";
export class MissingPathError extends Error {
message = "Missing path argument.";
}
export class MissingBodyError extends Error {
message =
"If the HTTP method is POST, a body must be provided in the `options` object";
}
/**
*
* @typedef {Object} State
* @property {null|any} data
* @property {null|Error} error
* @property {boolean} loading
*/
/**
* @typedef {Object} Action
* @param {"REQUEST_INITIALISED"|"REQUEST_SUCCEEDED"|"REQUEST_FAILED"} type
* @param {Error} [error]
* @param {any} [data]
*/
/**
* @param {State} state
* @param {Action} action
* @returns {State}
*/
export function useRestApiReducer(state, action) {
switch (action.type) {
case "REQUEST_INITIALISED":
return { ...state, error: null, loading: true };
case "REQUEST_SUCCEEDED":
return { data: action.data, error: null, loading: false };
case "REQUEST_FAILED":
return { ...state, error: action.error, loading: false };
default:
throw new Error();
}
}
export function useRestApi({ path, method = "get", options = {} }) {
if (path == null) throw new MissingPathError();
if (method === "post" && options.body == null) throw new MissingBodyError();
// WHY? the function fails if I dinnae do this, goes into an infinite loop:
const opts = React.useRef(options);
const [state, dispatch] = React.useReducer(useRestApiReducer, {
data: null,
error: null,
loading: false,
});
React.useEffect(() => {
async function fetch({ path, method = "get", options = {} }) {
dispatch({ type: "REQUEST_INITIALISED" });
try {
const response = await API[method](path, options);
if (response.status >= 200 && response.status <= 299) {
dispatch({ type: "REQUEST_SUCCEEDED", data: response.data });
} else {
throw new Error(`Error ${statusCode}, request cannot complete.`);
}
} catch (error) {
dispatch({ type: "REQUEST_FAILED", error });
}
}
if (path !== "") fetch({ path, method, options: opts.current });
}, [method, path]);
return state;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment