Comparing version 0.4.0 to 0.4.1
@@ -52,10 +52,2 @@ "use strict"; | ||
var cacheLife = _a.cacheLife; | ||
var isExpired = function (responseID) { | ||
var cache = getCache(); | ||
var _a = (cache[responseID] || {}), expiration = _a.expiration, response = _a.response; | ||
var expired = expiration > 0 && expiration < Date.now(); | ||
if (expired) | ||
remove(responseID); | ||
return expired || !response; | ||
}; | ||
var remove = function () { | ||
@@ -76,2 +68,10 @@ var responseIDs = []; | ||
}; | ||
var isExpired = function (responseID) { | ||
var cache = getCache(); | ||
var _a = (cache[responseID] || {}), expiration = _a.expiration, response = _a.response; | ||
var expired = expiration > 0 && expiration < Date.now(); | ||
if (expired) | ||
remove(responseID); | ||
return expired || !response; | ||
}; | ||
var has = function (responseID) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { | ||
@@ -78,0 +78,0 @@ return [2 /*return*/, !isExpired(responseID)]; |
import { Cache } from '../types'; | ||
declare var getMemoryStorage: ({ cacheLife }: { | ||
declare const getMemoryStorage: ({ cacheLife }: { | ||
cacheLife: number; | ||
}) => Cache; | ||
export default getMemoryStorage; |
@@ -42,2 +42,19 @@ "use strict"; | ||
var cacheLife = _a.cacheLife; | ||
var remove = function () { | ||
var responseIDs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
responseIDs[_i] = arguments[_i]; | ||
} | ||
return __awaiter(void 0, void 0, void 0, function () { | ||
var _a, responseIDs_1, responseID; | ||
return __generator(this, function (_b) { | ||
for (_a = 0, responseIDs_1 = responseIDs; _a < responseIDs_1.length; _a++) { | ||
responseID = responseIDs_1[_a]; | ||
delete inMemoryStorage[responseID]; | ||
delete inMemoryStorage[responseID + ":ts"]; | ||
} | ||
return [2 /*return*/]; | ||
}); | ||
}); | ||
}; | ||
var isExpired = function (responseID) { | ||
@@ -48,3 +65,3 @@ var expiration = inMemoryStorage[responseID + ":ts"]; | ||
remove(responseID); | ||
return expired; | ||
return expired || !inMemoryStorage[responseID]; | ||
}; | ||
@@ -68,19 +85,2 @@ var get = function (responseID) { return __awaiter(void 0, void 0, void 0, function () { | ||
}); }); }; | ||
var remove = function () { | ||
var responseIDs = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
responseIDs[_i] = arguments[_i]; | ||
} | ||
return __awaiter(void 0, void 0, void 0, function () { | ||
var _a, responseIDs_1, responseID; | ||
return __generator(this, function (_b) { | ||
for (_a = 0, responseIDs_1 = responseIDs; _a < responseIDs_1.length; _a++) { | ||
responseID = responseIDs_1[_a]; | ||
delete inMemoryStorage[responseID]; | ||
delete inMemoryStorage[responseID + ":ts"]; | ||
} | ||
return [2 /*return*/]; | ||
}); | ||
}); | ||
}; | ||
var clear = function () { return __awaiter(void 0, void 0, void 0, function () { | ||
@@ -87,0 +87,0 @@ return __generator(this, function (_a) { |
@@ -124,3 +124,3 @@ import { ReactNode } from 'react'; | ||
request?: (options: Options, url: string, path: string, route: string) => Promise<Options> | Options; | ||
response?: (response: Res<any>) => Res<any>; | ||
response?: (response: Res<any>) => Promise<Res<any>>; | ||
}; | ||
@@ -127,0 +127,0 @@ export declare type Cache = { |
@@ -84,7 +84,7 @@ "use strict"; | ||
var forceUpdate = react_1.useReducer(function () { return ({}); }, [])[1]; | ||
var makeFetch = react_1.useCallback(function (method) { | ||
var makeFetch = utils_1.useDeepCallback(function (method) { | ||
var doFetch = function (routeOrBody, body) { return __awaiter(_this, void 0, void 0, function () { | ||
var theController, _a, url, options, response, _b, err_1, timer, newData, newRes, err_2; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
var theController, _a, url, options, response, _b, err_1, timer, newData, newRes, _c, _d, err_2; | ||
return __generator(this, function (_e) { | ||
switch (_e.label) { | ||
case 0: | ||
@@ -98,3 +98,3 @@ if (isServer) | ||
case 1: | ||
_a = _c.sent(), url = _a.url, options = _a.options, response = _a.response; | ||
_a = _e.sent(), url = _a.url, options = _a.options, response = _a.response; | ||
if (!suspense && mounted.current) | ||
@@ -104,5 +104,5 @@ setLoading(true); | ||
if (!(response.isCached && cachePolicy === CACHE_FIRST)) return [3 /*break*/, 5]; | ||
_c.label = 2; | ||
_e.label = 2; | ||
case 2: | ||
_c.trys.push([2, 4, , 5]); | ||
_e.trys.push([2, 4, , 5]); | ||
res.current = response.cached; | ||
@@ -112,3 +112,3 @@ _b = res.current; | ||
case 3: | ||
_b.data = _c.sent(); | ||
_b.data = _e.sent(); | ||
data.current = res.current.data; | ||
@@ -119,3 +119,3 @@ if (!suspense && mounted.current) | ||
case 4: | ||
err_1 = _c.sent(); | ||
err_1 = _e.sent(); | ||
error.current = err_1; | ||
@@ -135,8 +135,8 @@ if (mounted.current) | ||
}, timeout); | ||
_c.label = 6; | ||
_e.label = 6; | ||
case 6: | ||
_c.trys.push([6, 11, 12, 13]); | ||
_e.trys.push([6, 14, 15, 16]); | ||
return [4 /*yield*/, fetch(url, options)]; | ||
case 7: | ||
newRes = _c.sent(); | ||
newRes = _e.sent(); | ||
res.current = newRes.clone(); | ||
@@ -146,9 +146,19 @@ if (!(cachePolicy === CACHE_FIRST)) return [3 /*break*/, 9]; | ||
case 8: | ||
_c.sent(); | ||
_c.label = 9; | ||
_e.sent(); | ||
_e.label = 9; | ||
case 9: return [4 /*yield*/, utils_1.tryGetData(newRes, defaults.data)]; | ||
case 10: | ||
newData = _c.sent(); | ||
newData = _e.sent(); | ||
res.current.data = onNewData(data.current, newData); | ||
res.current = interceptors.response ? interceptors.response(res.current) : res.current; | ||
_c = res; | ||
if (!interceptors.response) return [3 /*break*/, 12]; | ||
return [4 /*yield*/, interceptors.response(res.current)]; | ||
case 11: | ||
_d = _e.sent(); | ||
return [3 /*break*/, 13]; | ||
case 12: | ||
_d = res.current; | ||
_e.label = 13; | ||
case 13: | ||
_c.current = _d; | ||
utils_1.invariant('data' in res.current, 'You must have `data` field on the Response returned from your `interceptors.response`'); | ||
@@ -158,5 +168,5 @@ data.current = res.current.data; | ||
hasMore.current = false; | ||
return [3 /*break*/, 13]; | ||
case 11: | ||
err_2 = _c.sent(); | ||
return [3 /*break*/, 16]; | ||
case 14: | ||
err_2 = _e.sent(); | ||
if (attempts.current > 0) | ||
@@ -168,4 +178,4 @@ return [2 /*return*/, doFetch(routeOrBody, body)]; | ||
error.current = err_2; | ||
return [3 /*break*/, 13]; | ||
case 12: | ||
return [3 /*break*/, 16]; | ||
case 15: | ||
if (newRes && !newRes.ok && !error.current) | ||
@@ -180,3 +190,3 @@ error.current = { name: newRes.status, message: newRes.statusText }; | ||
return [7 /*endfinally*/]; | ||
case 13: | ||
case 16: | ||
if (!suspense && mounted.current) | ||
@@ -244,11 +254,10 @@ setLoading(false); | ||
} | ||
return function () { return mounted.current = false; }; | ||
// TODO: need [request] in dependency array. Causing infinite loop though. | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
// onUnmount | ||
return function () { | ||
// Cancel any running request when unmounting to avoid updating state after component has unmounted | ||
// This can happen if a request's promise resolves after component unmounts | ||
request.abort(); | ||
mounted.current = false; | ||
}; | ||
}, dependencies); | ||
// Cancel any running request when unmounting to avoid updating state after component has unmounted | ||
// This can happen if a request's promise resolves after component unmounts | ||
// TODO: should have [request.abort] in dependency array. Causing every request to be aborted though... | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
react_1.useEffect(function () { return request.abort; }, []); | ||
if (suspense && suspender.current) { | ||
@@ -255,0 +264,0 @@ if (isServer) |
@@ -1,3 +0,3 @@ | ||
import { MutableRefObject } from 'react'; | ||
import { OptionsMaybeURL, Res } from './types'; | ||
import { MutableRefObject, DependencyList } from 'react'; | ||
import { OptionsMaybeURL, Res, HTTPMethod } from './types'; | ||
import { FunctionKeys, NonFunctionKeys } from 'utility-types'; | ||
@@ -62,2 +62,3 @@ /** | ||
}>; | ||
export declare const useDeepCallback: (cb: (method: HTTPMethod) => (...args: any) => any, deps: DependencyList) => (method: HTTPMethod) => (...args: any) => any; | ||
export {}; |
@@ -247,2 +247,9 @@ "use strict"; | ||
}); }; | ||
function useDeepCompareMemoize(value) { | ||
var ref = react_1.useRef(); | ||
if (JSON.stringify(value) !== JSON.stringify(ref.current)) | ||
ref.current = value; | ||
return ref.current; | ||
} | ||
exports.useDeepCallback = function (cb, deps) { return react_1.useCallback(cb, useDeepCompareMemoize(deps)); }; | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "use-http", | ||
"version": "0.4.0", | ||
"version": "0.4.1", | ||
"homepage": "http://use-http.com", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -109,8 +109,5 @@ [![use-http logo][3]][5] | ||
// componentDidMount | ||
const mounted = useRef(false) | ||
useEffect(() => { | ||
if (mounted.current) return | ||
mounted.current= true | ||
initializeTodos() | ||
}) | ||
}, []) | ||
@@ -255,6 +252,4 @@ async function initializeTodos() { | ||
const mounted = useRef(false) | ||
// componentDidMount | ||
useEffect(() => { | ||
if (mounted.current) return | ||
mounted.current = true | ||
loadInitialTodos() | ||
@@ -637,8 +632,8 @@ }, []) | ||
// every time we make an http request, before getting the response back, this will run | ||
response: (response) => { | ||
response: async (response) => { | ||
// unfortunately, because this is a JS Response object, we have to modify it directly. | ||
// It shouldn't have any negative affect since this is getting reset on each request. | ||
// use "eslint-disable-next-line" if you're getting linting errors. | ||
if (response.data) response.data = toCamel(response.data) | ||
return response | ||
const res = response | ||
if (res.data) res.data = toCamel(res.data) | ||
return res | ||
} | ||
@@ -849,6 +844,7 @@ } | ||
request: async (options, url, path, route) => { // `async` is not required | ||
return options // returning the `options` is important | ||
return options // returning the `options` is important | ||
}, | ||
response: (response) => { | ||
return response // returning the `response` is important | ||
response: async (response) => { | ||
// note: `response.data` is equivalent to `await response.json()` | ||
return response // returning the `response` is important | ||
} | ||
@@ -912,3 +908,2 @@ } | ||
- [ ] tests | ||
- [ ] doFetchArgs tests for `response.isExpired` | ||
- [ ] tests for SSR | ||
@@ -919,2 +914,4 @@ - [ ] tests for FormData (can also do it for react-native at same time. [see here](https://stackoverflow.com/questions/45842088/react-native-mocking-formdata-in-unit-tests)) | ||
- [ ] tests to make sure `response.formData()` and some of the other http `response methods` work properly | ||
- [ ] the `onMount` works properly with all variants of passing `useEffect(fn, [request.get])` and not causing an infinite loop | ||
- [ ] `async` tests for `interceptors.response` | ||
- [ ] aborts fetch on unmount | ||
@@ -961,3 +958,3 @@ - [ ] take a look at how [react-apollo-hooks](https://github.com/trojanowski/react-apollo-hooks) work. Maybe ad `useSubscription` and `const request = useFetch(); request.subscribe()` or something along those lines | ||
request: async ({ options, url, path, route }) => {}, | ||
response: ({ response }) => {} | ||
response: async ({ response }) => {} | ||
}, | ||
@@ -964,0 +961,0 @@ // can retry on certain http status codes |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
153625
1687
1046