UNPKG

react-fetching-library-extended

Version:

Simple and powerful API client for react. Use hooks or FACC's to fetch data in easy way. No dependencies! Just react under the hood.

42 lines (39 loc) 12.3 kB
/* ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *****************************************************************************/ 'use strict';Object.defineProperty(exports,"__esModule",{value:!0});var React=require("react");function _interopDefaultLegacy(a){return a&&"object"===typeof a&&"default"in a?a:{"default":a}}var React__default=_interopDefaultLegacy(React); function __rest(a,b){var c={},d;for(d in a)Object.prototype.hasOwnProperty.call(a,d)&&0>b.indexOf(d)&&(c[d]=a[d]);if(null!=a&&"function"===typeof Object.getOwnPropertySymbols){var e=0;for(d=Object.getOwnPropertySymbols(a);e<d.length;e++)0>b.indexOf(d[e])&&Object.prototype.propertyIsEnumerable.call(a,d[e])&&(c[d[e]]=a[d[e]])}return c} function __awaiter(a,b,c,d){function e(g){return g instanceof c?g:new c(function(h){h(g)})}return new (c||(c=Promise))(function(g,h){function k(f){try{m(d.next(f))}catch(l){h(l)}}function n(f){try{m(d["throw"](f))}catch(l){h(l)}}function m(f){f.done?g(f.value):e(f.value).then(k,n)}m((d=d.apply(a,b||[])).next())})}let convertActionKey=a=>a.endpoint+a.method; class CacheStore{constructor(){this.value={};this.callbacks={updated:[]};this.getValue=()=>this.value;this.setValue=a=>{this.value=a;this.callbacks.updated.forEach(b=>b())};this.getResponse=a=>this.value[convertActionKey(a)];this.setResponse=(a,b)=>{this.value[convertActionKey(a)]=b;this.callbacks.updated.forEach(c=>c())};this.removeResponse=a=>{delete this.value[convertActionKey(a)];this.callbacks.updated.forEach(b=>b())};this.getPayload=a=>{var b;return null===(b=this.getResponse(a))||void 0=== b?void 0:b.payload};this.updatePayload=(a,b)=>{this.setResponse(a,Object.assign(Object.assign({},this.getResponse(a)),{payload:b}))};this.on=(a,b)=>{this.callbacks[a].push(b)};this.off=(a,b)=>{this.callbacks[a]=this.callbacks[a].filter(c=>c!==b)}}}class SuspenseCacheStore{constructor(){this.value={};this.get=a=>this.value[convertActionKey(a)];this.add=(a,b)=>{this.value[convertActionKey(a)]=b};this.remove=a=>{delete this.value[convertActionKey(a)]}}} class RequestStore{constructor(){this.value={};this.add=(a,b,c)=>{this.value[convertActionKey(a)]=b;(null===c||void 0===c?0:c.removeTimeout)&&b.then(()=>{setTimeout(()=>this.remove(a),c.removeTimeout)});(null===c||void 0===c?0:c.removeOnError)&&b.catch(()=>this.remove(a))};this.remove=a=>{a=convertActionKey(a);delete this.value[a]};this.get=a=>this.value[convertActionKey(a)];this.has=a=>!!this.value[convertActionKey(a)]}} class QueryError extends Error{constructor(a,b){super(a);Object.setPrototypeOf(this,QueryError.prototype);this.name="QueryError";this.response=b}} let createClient=(a={})=>{const b=new CacheStore,c=new SuspenseCacheStore,d=new RequestStore,e=(k,n)=>__awaiter(void 0,void 0,void 0,function*(){const [m,...f]=n;return m?yield e(yield m(h)(k),f):k}),g=(k,n,m)=>__awaiter(void 0,void 0,void 0,function*(){const [f,...l]=m;return f?yield g(k,yield f(h)(k,n),l):n}),h={cache:b,suspenseCache:c,query:(k,n=!1)=>__awaiter(void 0,void 0,void 0,function*(){var m;try{if(!n){const y=b.getResponse(k);if(y)return y}const f=yield e(k,a.requestInterceptors||[]),{endpoint:l, body:p,responseType:t}=f,q=__rest(f,["endpoint","body","responseType"]);let r=q.headers;p&&(p instanceof FormData||p instanceof Blob||p instanceof ArrayBuffer)||(r=Object.assign({"Content-Type":"application/json; charset=utf-8"},q.headers));const u=r&&r["Content-Type"]&&-1!==r["Content-Type"].indexOf("json"),x=!d.has(k),v=a.fetch||fetch;x&&d.add(k,v(l,Object.assign(Object.assign({},q),{body:p?u?JSON.stringify(p):p:void 0,headers:r,responseType:t})).then(y=>__awaiter(void 0,void 0,void 0,function*(){const A= yield resolveResponse(y,t);return{response:y,payload:A}})),{removeTimeout:null!==(m=null===a||void 0===a?void 0:a.dedupingInterval)&&void 0!==m?m:2E3,removeOnError:!0});const {response:w,payload:B}=yield d.get(k),z=yield g(f,{error:!w.ok,headers:w.headers,payload:B,status:w.status},a.responseInterceptors||[]);if(z.status&&f.config&&f.config.emitErrorForStatuses&&f.config.emitErrorForStatuses.includes(z.status))throw new QueryError("request-error",z);w.ok&&"GET"===k.method&&b.setResponse(k,z);return z}catch(f){return{error:!0, errorObject:f}}})};return h};function resolveResponse(a,b){return __awaiter(this,void 0,void 0,function*(){if(b)return a[b]();let c=a.headers.get("Content-Type");return-1===[204,205].indexOf(a.status)&&c&&-1!==c.indexOf("json")?yield a.json():yield a.text()})} let initialContext={query:()=>{console.warn("Add ClientProvider to use client context");return Promise.resolve({error:!0,status:0})},cache:new CacheStore,suspenseCache:new SuspenseCacheStore},ClientContext=React.createContext(initialContext),SET_LOADING="response/loading",RESET_LOADING="response/reset-loading",RESET="response/reset",SET_RESPONSE="response/set",responseReducer=(a,b)=>{switch(b.type){case SET_LOADING:return Object.assign(Object.assign({},a),{loading:!0});case RESET_LOADING:return Object.assign(Object.assign({}, a),{loading:!1});case SET_RESPONSE:if(!b.response)throw Error();return Object.assign(Object.assign({},a),{loading:!1,response:b.response});case RESET:return{loading:!1,response:{error:!1}};default:throw Error();}},useQuery=(a,{initFetch:b=!0,skipCache:c=!1,pollInterval:d}={})=>{const e=React.useContext(ClientContext),g=React.useRef(!0),h=React.useRef(),k=c?null:e.cache.getResponse(a),[n,m]=React.useReducer(responseReducer,{loading:k?!1:b,response:k?k:{error:!1}});var f=convertActionKey(a);const l= ()=>{const r=e.cache.getResponse(a);r&&n.response!==r&&m({type:SET_RESPONSE,response:r})};React.useEffect(()=>{g.current=!0;b&&!k&&p(c);return()=>{g.current=!1;t()}},[f]);React.useEffect(()=>{let r=null;d&&(r=window.setInterval(()=>{p(!0)},d));return()=>{r&&(clearInterval(r),r=null)}},[f,d]);React.useEffect(l,[f]);React.useEffect(()=>{e.cache.on("updated",l);return()=>{e.cache.off("updated",l)}},[f,n.response]);const p=React.useCallback((r=!1)=>__awaiter(void 0,void 0,void 0,function*(){var u;const x= "AbortController"in window?new AbortController:void 0;var v=a.signal||(x?x.signal:void 0);h.current&&h.current.abort();h.current=x;if(!g.current)return{error:!1};m({type:SET_LOADING});v=yield e.query(Object.assign(Object.assign({},a),{signal:a.signal||v}),r);const w="AbortError"===(null===(u=v.errorObject)||void 0===u?void 0:u.name);u=e.cache.getResponse(a)===v;!g.current||w||u||m({type:SET_RESPONSE,response:v});g.current&&w&&h.current&&h.current===x&&(h.current=void 0,m({type:RESET_LOADING}));return v}), [f,e.query]);f=React.useCallback(()=>p(!0),[p]);const t=React.useCallback(()=>{h.current&&h.current.abort()},[]),q=React.useCallback(()=>{m({type:RESET})},[]);if(n.response&&n.response.errorObject&&n.response.errorObject instanceof QueryError)throw n.response.errorObject;return Object.assign({abort:t,loading:n.loading,query:f,reset:q},n.response)},useMutation=a=>{const b=React.useContext(ClientContext),c=React.useRef(!0),d=React.useRef(),[e,g]=React.useReducer(responseReducer,{loading:!1,response:{error:!1}}); React.useEffect(()=>{c.current=!0;return()=>{c.current=!1;k()}},[]);const h=React.useCallback((...m)=>__awaiter(void 0,void 0,void 0,function*(){var f;if(!c.current)return{error:!1};var l=a(...m);const p="AbortController"in window?new AbortController:void 0,t=l.signal||(p?p.signal:void 0);d.current&&d.current.abort();d.current=p;g({type:SET_LOADING});l=yield b.query(Object.assign(Object.assign({},l),{signal:l.signal||t}));!c.current||l.errorObject&&"AbortError"===l.errorObject.name||g({type:SET_RESPONSE, response:l});c.current&&"AbortError"===(null===(f=l.errorObject)||void 0===f?void 0:f.name)&&d.current&&d.current===p&&(d.current=void 0,g({type:RESET_LOADING}));return l}),[a,b.query]),k=React.useCallback(()=>{d.current&&d.current.abort()},[]),n=React.useCallback(()=>{g({type:RESET})},[]);if(e.response&&e.response.errorObject&&e.response.errorObject instanceof QueryError)throw e.response.errorObject;return Object.assign({abort:k,loading:e.loading,mutate:h,reset:n},e.response)},useBulkMutation=a=> {const {query:b}=React.useContext(ClientContext),c=React.useRef(!0),d=React.useRef(),[e,g]=React.useState({loading:!1,responses:[]}),h=React.useCallback(()=>{d.current&&d.current.abort()},[d]);React.useEffect(()=>{c.current=!0;return()=>{c.current=!1;h()}},[h]);const k=React.useCallback(m=>__awaiter(void 0,void 0,void 0,function*(){if(!c.current)return Array.from(Array(10).keys()).map(()=>({error:!1}));const f="AbortController"in window?new AbortController:void 0,l=m.map(q=>a(q)),p=f?f.signal:void 0; l.forEach(q=>q.signal=q.signal||p);d.current&&d.current.abort();d.current=f;g(q=>Object.assign(Object.assign({},q),{loading:!0}));const t=yield Promise.all(l.map(q=>b(q)));c.current&&g({loading:!1,responses:t.map((q,r)=>{if(!q.errorObject||"AbortError"!==q.errorObject.name)return l[r].signal===p&&d.current===f&&(d.current=void 0,g(u=>Object.assign(Object.assign({},u),{loading:!1}))),q})});return t}),[b,a]),n=React.useCallback(()=>{g({loading:!1,responses:[]})},[g]);return{abort:h,loading:e.loading, mutate:k,reset:n,responses:e.responses}},useSuspenseQuery=a=>{const b=React.useContext(ClientContext),[c,d]=React.useState(null),e=b.suspenseCache.get(a);React.useEffect(()=>{e&&e.response&&null!==c&&b.suspenseCache.remove(a);return()=>{b.suspenseCache.remove(a)}},[convertActionKey(a)]);const g=()=>{b.suspenseCache.remove(a);d(!c)};if(e){if(e.response){if(e.response.errorObject&&e.response.errorObject instanceof QueryError)throw e.response.errorObject;return Object.assign(Object.assign({},e.response), {query:g})}throw e.fetch;}const h=b.query(a,null!==c).then(k=>{b.suspenseCache.add(a,{fetch:h,response:k})});b.suspenseCache.add(a,{fetch:h});throw h;},useCachedResponse=a=>{const b=React.useContext(ClientContext),[c,d]=React.useState(b.cache.getResponse(a));React.useEffect(()=>{const e=()=>{const g=b.cache.getResponse(a);g!==c&&d(g)};b.cache.on("updated",e);return()=>{b.cache.off("updated",e)}},[convertActionKey(a),c]);return c},useClient=()=>React.useContext(ClientContext),useParameterizedQuery= a=>{var b=useMutation(a);({mutate:a}=b);b=__rest(b,["mutate"]);return Object.assign(Object.assign({},b),{query:a})},Query=({action:a,children:b,initFetch:c=!0})=>{a=useQuery(a,{initFetch:c});return b(a)},Mutation=({actionCreator:a,children:b})=>{a=useMutation(a);return b(a)},SuspenseQuery=({action:a,children:b})=>{a=useSuspenseQuery(a);return b(a)}; class QueryErrorBoundary extends React.Component{constructor(a){super(a);this.state={hasError:!1};this.restart=()=>{this.setState({hasError:!1,response:void 0})};this.state={hasError:!1,response:void 0}}static getDerivedStateFromError(a){if(a instanceof QueryError)return{hasError:!0,response:a.response}}render(){return this.state.hasError&&this.state.response&&this.state.response.status&&this.props.statuses.includes(this.state.response.status)?this.props.fallback(this.state.response,this.restart): this.props.children}}let ClientContextProvider=({client:a,children:b})=>React__default["default"].createElement(ClientContext.Provider,{value:{query:a.query,cache:a.cache,suspenseCache:a.suspenseCache}},b);exports.ClientContext=ClientContext;exports.ClientContextProvider=ClientContextProvider;exports.Mutation=Mutation;exports.Query=Query;exports.QueryError=QueryError;exports.QueryErrorBoundary=QueryErrorBoundary;exports.SuspenseQuery=SuspenseQuery;exports.createClient=createClient; exports.useBulkMutation=useBulkMutation;exports.useCachedResponse=useCachedResponse;exports.useClient=useClient;exports.useMutation=useMutation;exports.useParameterizedQuery=useParameterizedQuery;exports.useQuery=useQuery;exports.useSuspenseQuery=useSuspenseQuery