UNPKG

@pinkairship/use-data-fetch

Version:

A data fetch hook that stays out of your way.

169 lines (162 loc) 4.69 kB
import { useState, useCallback } from 'react' import { useFetchOnMount } from './use-fetch-on-mount' const passThrough = (data) => data const getArray = (data) => { if (Array.isArray(data)) { return data } if (Object.keys(data).length == 1) { const arr = data[Object.keys(data)[0]] if (Array.isArray(arr)) { return data[Object.keys(data)[0]] } } throw new Error( 'Your data does not have a recognized pattern. Please provide your own transform function.' ) } function getKey(data) { if (!data.id) { throw new Error( 'Cannot use default extractObjectKey for objects that do not have an id field.' ) } return data.id } export function useFetchedArray( path, { onSuccess: onSuccess, onFailure: onFailure, hookOptions: hookOptions, transform: transform, extractList: extractList, replaceValue: replaceValue, removeValue: removeValue, updatesUsePath: updatesUsePath, extractObjectKey: extractObjectKey, cancelRequestOnUnmount: cancelRequestOnUnmount, } = { onSuccess: passThrough, onFailure: passThrough, hookOptions: {}, transform: passThrough, extractList: getArray, replaceValue: null, removeValue: null, updatesUsePath: null, extractObjectKey: getKey, cancelRequestOnUnmount: false, } ) { // TODO: the defaults for the above are not set when built, figure it out // and these can be removed extractList = extractList ? extractList : getArray onSuccess = onSuccess ? onSuccess : passThrough onFailure = onFailure ? onFailure : passThrough transform = transform ? transform : passThrough extractObjectKey = extractObjectKey ? extractObjectKey : getKey ////// const [values, setValues] = useState([]) const [requestState, setRequestState] = useState('pending') const updateStateHook = useCallback( ({ data }) => { const newValues = extractList(data) setValues(newValues) }, [extractList] ) const dataFetch = useFetchOnMount(path, { onSuccess: onSuccess, onFailure: onFailure, hookOptions: { ...hookOptions, requestStateListener: setRequestState, updateStateHook, }, cancelRequestOnUnmount: cancelRequestOnUnmount, }) const updateValue = replaceValue ? replaceValue : ({ data }) => { const newData = transform(data) const objectKey = extractObjectKey(newData) setValues((state) => { const oldValueIndex = state.findIndex( (v) => v.id == objectKey ) const newValues = [...state] newValues[oldValueIndex] = newData return newValues }) } const updatePath = updatesUsePath ? updatesUsePath(path) : (data) => `${path}/${data.id}` const managedDataFetch = { get: dataFetch.get, post: (postData, opts = {}) => { const postUpdateStateHook = ({ data }) => { let newValues = transform(data) newValues = Array.isArray(newValues) ? newValues : [newValues] setValues((state) => [...state, ...newValues]) } return dataFetch.post(postData, { updateStateHook: postUpdateStateHook, ...opts, }) }, put: (putData, opts = {}) => { return dataFetch.put(putData, { updateStateHook: updateValue, requestConfig: { url: updatePath(putData), }, ...opts, }) }, patch: (patchData, opts = {}) => { return dataFetch.patch(patchData, { updateStateHook: updateValue, requestConfig: { url: updatePath(patchData), }, ...opts, }) }, destroy: (destroyData, removalKeys, opts = {}) => { const removeKeyValue = (removalKey) => { setValues((state) => { const valueIndex = state.findIndex( (j) => j.id === removalKey ) const newValues = [...state] newValues.splice(valueIndex, 1) return newValues }) } const destroyUpdateStateHook = removeValue ? removeValue : () => { if ( removalKeys != undefined && Array.isArray(removalKeys) ) { removalKeys.forEach((removalKey) => { removeKeyValue(removalKey) }) } else { removeKeyValue(removalKeys) } } return dataFetch.destroy(destroyData, { updateStateHook: destroyUpdateStateHook, requestConfig: { url: updatePath(destroyData), }, ...opts, }) }, } return [values, setValues, requestState, managedDataFetch] }