Last active
June 16, 2020 13:15
-
-
Save isocroft/1de349e7abf868618b5eedf4059a660e to your computer and use it in GitHub Desktop.
A React Hook for fetching data and notifying all other components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from 'preact/hooks'; | |
import fetch from 'isomorphic-fetch'; | |
/** | |
* `useSync` was created to abstract the stateful logic for managing rest/graphql | |
* requests ( fetches / queries / mutations ) in such a manner as to not repeat similar logic | |
* in different components across the project and to be made instantly reusable in | |
* these components. The implementation is highly functional | |
* ( lots of function composition and argument currying ). | |
* | |
* Also, `useFetch` was created to abstract the implementation of the `isLoading` state | |
* of any component very trivial (while the component is waiting for data from the | |
* server [ queries ] OR while the component is waiting for data being sent to the | |
* server to be fulfilled [ mutations ]) which i believe is crucial to presenting | |
* visual cues for pending activity to the end user. | |
* | |
* @param {mixed} defaultFetchData | |
* @param {mixed} defaultFetchError | |
* @param {Function} customizePayload | |
* | |
* @returns {Object} | |
*/ | |
const useFetch = ( | |
defaultFetchData = null, | |
defaultFetchError = null, | |
customizePayload = r => { | |
return r; | |
} | |
) => { | |
const [fetchData, setFetchData] = useState(defaultFetchData); | |
const [fetchError, setFetchError] = useState(defaultFetchError); | |
const [isPending, setIsPending] = useState(true); | |
const _fetch = (urlOrQuery, params = null) => { | |
setIsPending(true); | |
return fetch(urlOrQuery, params) | |
.then(function onData(payload) { | |
if (payload.error) throw payload.error; | |
setFetchData(customizePayload(payload.response, 'response')); | |
return emitToAll(urlOrQuery, payload.response); | |
}) | |
.catch(function onError(payload) { | |
setFetchError( | |
customizePayload( | |
payload instanceof Error ? payload : payload.error, | |
'error' | |
) | |
); | |
}) | |
.finally(function onFinish() { | |
setIsPending(false); | |
}); | |
}; | |
const connectToFetcher = templateFunction => { | |
return typeof templateFunction === 'function' | |
? templateFunction.bind(null, _fetch) | |
: templateFunction; | |
}; | |
const connectToReporter = (templateFunction, isErrorReporter = false) => { | |
return typeof templateFunction === 'function' | |
? templateFunction.bind( | |
null, | |
isErrorReporter ? setFetchError : setFetchData | |
) | |
: templateFunction; | |
}; | |
const connectToFetcherAndReporter = templateFunction => { | |
return typeof templateFunction === 'function' | |
? connectToReporter(connectToFetcher(templateFunction), true) | |
: templateFunction; | |
}; | |
return { | |
connectToFetcherAndReporter, | |
fetch:_fetch, | |
fetchData, | |
fetchError, | |
isLoading | |
}; | |
}; | |
export { useFetch }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment