Repository: zeit/swr
Pull request #221 (2020-01-06 19:36:45)

Moving page cache to use a cache map
Currently, changing the pageKey doesn't reset the pages cache, and theres no other way to clear the pages cache.

Might solve #189


Patch:
diff --git a/src/config.ts b/src/config.ts
index 4db8024..0ad426f 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -1,3 +1,4 @@
+import deepEqual from 'fast-deep-equal'
 import isDocumentVisible from './libs/is-document-visible'
 import isOnline from './libs/is-online'
 import {
@@ -76,7 +77,8 @@ const defaultConfig: ConfigInterface = {
   refreshWhenHidden: false,
   refreshWhenOffline: false,
   shouldRetryOnError: true,
-  suspense: false
+  suspense: false,
+  compare: deepEqual
 }
 
 // Focus revalidate
diff --git a/src/types.ts b/src/types.ts
index c4d42ad..eb080eb 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -37,6 +37,8 @@ export interface ConfigInterface<
     revalidate: revalidateType,
     revalidateOpts: RevalidateOptionInterface
   ) => void
+
+  compare?: (a: Data | undefined, b: Data | undefined) => boolean
 }
 
 export interface RevalidateOptionInterface {
diff --git a/src/use-swr-pages.tsx b/src/use-swr-pages.tsx
index 2baa17a..9affe92 100644
--- a/src/use-swr-pages.tsx
+++ b/src/use-swr-pages.tsx
@@ -88,6 +88,8 @@ function App () {
 }
 */
 
+const pageCacheMap = new Map()
+
 export function useSWRPages<OffsetType = any, Data = any, Error = any>(
   pageKey: string,
   pageFn: pageComponentType<OffsetType, Data, Error>,
@@ -105,7 +107,6 @@ export function useSWRPages<OffsetType = any, Data = any, Error = any>(
   )
   const [pageSWRs, setPageSWRs] = useState<responseInterface<Data, Error>[]>([])
 
-  const pageCacheRef = useRef([])
   const pageFnRef = useRef(pageFn)
   const emptyPageRef = useRef(false)
 
@@ -176,7 +177,10 @@ export function useSWRPages<OffsetType = any, Data = any, Error = any>(
 
     // render each page
     const p = []
-    const pageCache = pageCacheRef.current
+    if (!pageCacheMap.has(pageKey)) {
+      pageCacheMap.set(pageKey, [])
+    }
+    const pageCache = pageCacheMap.get(pageKey)
     for (let i = 0; i < pageCount; ++i) {
       if (
         !pageCache[i] ||
diff --git a/src/use-swr.ts b/src/use-swr.ts
index f873a5a..8dade51 100644
--- a/src/use-swr.ts
+++ b/src/use-swr.ts
@@ -1,4 +1,3 @@
-import deepEqual from 'fast-deep-equal'
 import {
   useCallback,
   useContext,
@@ -309,7 +308,7 @@ function useSWR<Data = any, Error = any>(
           // we don't have an error
           newState.error = undefined
         }
-        if (deepEqual(stateRef.current.data, newData)) {
+        if (config.compare(stateRef.current.data, newData)) {
           // deep compare to avoid extra re-render
           // do nothing
         } else {
@@ -384,7 +383,7 @@ function useSWR<Data = any, Error = any>(
     // update the state if the key changed or cache updated
     if (
       keyRef.current !== key ||
-      !deepEqual(currentHookData, latestKeyedData)
+      !config.compare(currentHookData, latestKeyedData)
     ) {
       dispatch({ data: latestKeyedData })
       keyRef.current = key
@@ -434,7 +433,7 @@ function useSWR<Data = any, Error = any>(
 
       if (
         typeof updatedData !== 'undefined' &&
-        !deepEqual(stateRef.current.data, updatedData)
+        !config.compare(stateRef.current.data, updatedData)
       ) {
         newState.data = updatedData
         needUpdate = true
@@ -471,7 +470,7 @@ function useSWR<Data = any, Error = any>(
 
     // set up reconnecting when the browser regains network connection
     let reconnect = null
-    if (addEventListener && config.revalidateOnReconnect) {
+    if (typeof addEventListener !== 'undefined' && config.revalidateOnReconnect) {
       reconnect = addEventListener('online', softRevalidate)
     }
 
@@ -501,7 +500,7 @@ function useSWR<Data = any, Error = any>(
         }
       }
 
-      if (removeEventListener && reconnect !== null) {
+      if (typeof removeEventListener !== 'undefined' && reconnect !== null) {
         removeEventListener('online', reconnect)
       }
     }


Test patch:
diff --git a/test/use-swr.test.tsx b/test/use-swr.test.tsx
index 5f3e901..df29a33 100644
--- a/test/use-swr.test.tsx
+++ b/test/use-swr.test.tsx
@@ -464,6 +464,47 @@ describe('useSWR - refresh', () => {
     })
     expect(container.firstChild.textContent).toMatchInlineSnapshot(`"count: 5"`)
   })
+
+  it('should allow use custom isEqual method', async () => {
+    function Page() {
+      const { data, revalidate } = useSWR(
+        'dynamic-11',
+        () => ({
+          timestamp: +new Date(),
+          version: '1.0'
+        }),
+        {
+          compare: function isEqual(a, b) {
+            if (a === b) {
+              return true
+            }
+            if (!a || !b) {
+              return false
+            }
+            return a.version === b.version
+          }
+        }
+      )
+
+      if (!data) {
+        return <div>loading</div>
+      }
+      return <button onClick={revalidate}>{data.timestamp}</button>
+    }
+
+    const { container } = render(<Page />)
+
+    expect(container.firstChild.textContent).toMatchInlineSnapshot(`"loading"`)
+    await waitForDomChange({ container })
+    const firstContent = container.firstChild.textContent
+    await act(() => {
+      // trigger revalidation
+      fireEvent.click(container.firstElementChild)
+      return new Promise(res => setTimeout(res, 1))
+    })
+    const secondContent = container.firstChild.textContent
+    expect(firstContent).toEqual(secondContent)
+  })
 })
 
 describe('useSWR - revalidate', () => {