From eb196a2f23095495ab881419e8bb16e4857d2e96 Mon Sep 17 00:00:00 2001 From: Jacky Efendi Date: Fri, 29 May 2020 19:10:42 +0700 Subject: [PATCH] fix(core): fix possible memory leak on SSR and validate JSON on non-raw request --- .../src/common/Client.ts | 1 + .../react-isomorphic-data/src/common/types.ts | 1 + .../src/hooks/utils/useBaseData.ts | 20 +++++++++++-------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/react-isomorphic-data/src/common/Client.ts b/packages/react-isomorphic-data/src/common/Client.ts index c656274..c210e1c 100644 --- a/packages/react-isomorphic-data/src/common/Client.ts +++ b/packages/react-isomorphic-data/src/common/Client.ts @@ -16,6 +16,7 @@ export const createDataClient = ( headers: headers || {}, fetchPolicy: fetchPolicy || 'cache-first', toBePrefetched: {}, + __internal: {}, addSubscriber: (key: string, callback: Function) => { if (!(subscribers[key] instanceof Map)) { subscribers[key] = new Map(); diff --git a/packages/react-isomorphic-data/src/common/types.ts b/packages/react-isomorphic-data/src/common/types.ts index fc93f3b..6997c56 100644 --- a/packages/react-isomorphic-data/src/common/types.ts +++ b/packages/react-isomorphic-data/src/common/types.ts @@ -10,6 +10,7 @@ export interface DataClient { fetchPolicy: 'cache-first' | 'cache-and-network' | 'network-only'; test: boolean; headers: Record; + __internal: Record; addSubscriber: (key: string, callback: Function) => void; removeSubscriber: (key: string, callback: Function) => void; notifySubscribers: (key: string) => void; diff --git a/packages/react-isomorphic-data/src/hooks/utils/useBaseData.ts b/packages/react-isomorphic-data/src/hooks/utils/useBaseData.ts index 9dcc691..595a1cf 100644 --- a/packages/react-isomorphic-data/src/hooks/utils/useBaseData.ts +++ b/packages/react-isomorphic-data/src/hooks/utils/useBaseData.ts @@ -6,8 +6,6 @@ import { LazyDataState, DataHookOptions } from '../types'; import useFetchRequirements from './useFetchRequirements'; import useCacheSubscription, { LoadingSymbol } from './useCacheSubscription'; -const simpleCache: Record = {}; - const useBaseData = ( url: string, queryParams: Record = {}, @@ -48,7 +46,6 @@ const useBaseData = ( const delay = Date.now() - Number(client.initTime); if (delay <= client.ssrForceFetchDelay) { - console.log('set to cache-first') fetchPolicy = 'cache-first'; // force to 'cache-first' policy when using ssrForceFetchDelay } } @@ -59,6 +56,9 @@ const useBaseData = ( promiseRef.current = fetcher(fullUrl, finalFetchOpts) .then((result) => result.text()) .then((data) => { + if (!raw) { + JSON.parse(data); // check if valid JSON or not, will throw error if it is not + } // this block of code will cause 2 re-renders because React doesn't batch these 2 updates // https://twitter.com/dan_abramov/status/887963264335872000?lang=en // For React 16.x we can use `unstable_batchedUpdates()` to solve this @@ -105,7 +105,7 @@ const useBaseData = ( }); return promiseRef.current; - }, [addToCache, finalFetchOpts, fullUrl, isSSR, useTempData, fetcher, setState]); + }, [addToCache, finalFetchOpts, fullUrl, isSSR, useTempData, fetcher, setState, raw]); const memoizedFetchData = React.useCallback((): Promise => { const currentDataInCache = retrieveFromCache(fullUrl); @@ -190,13 +190,17 @@ const useBaseData = ( return usedData; } else { // else, we want the data in json form - if (!simpleCache[usedData]) { - simpleCache[usedData] = JSON.parse(usedData); + if (!client.__internal[usedData]) { + try { + client.__internal[usedData] = JSON.parse(usedData); + } catch (err) { + client.__internal[usedData] = null; + } } - return simpleCache[usedData]; + return client.__internal[usedData]; } - }, [usedData, raw]); + }, [usedData, raw, client]); return [ memoizedFetchData,