diff --git a/infinite/index.ts b/infinite/index.ts index b171aaac5..110e2daa2 100644 --- a/infinite/index.ts +++ b/infinite/index.ts @@ -115,9 +115,7 @@ export const infinite = ((useSWRNext: SWRHook) => let previousPageData = null for (let i = 0; i < pageSize; ++i) { - const [pageKey, pageArgs] = serialize( - getKey ? getKey(i, previousPageData) : null - ) + const [pageKey, pageArgs] = serialize(getKey(i, previousPageData)) if (!pageKey) { // `pageKey` is falsy, stop fetching new pages. @@ -208,7 +206,7 @@ export const infinite = ((useSWRNext: SWRHook) => let previousPageData = null for (let i = 0; i < pageSize; ++i) { - const [pageKey] = serialize(getKey ? getKey(i, previousPageData) : null) + const [pageKey] = serialize(getKey(i, previousPageData)) // Get the cached page data. const pageData = pageKey ? cache.get(pageKey) : UNDEFINED diff --git a/package.json b/package.json index cea75e522..409e502b9 100644 --- a/package.json +++ b/package.json @@ -75,8 +75,8 @@ "@testing-library/jest-dom": "5.14.1", "@testing-library/react": "12.0.0", "@types/react": "17.0.20", - "@typescript-eslint/eslint-plugin": "5.4.0", - "@typescript-eslint/parser": "5.4.0", + "@typescript-eslint/eslint-plugin": "5.8.0", + "@typescript-eslint/parser": "5.8.0", "bunchee": "1.7.1", "eslint": "8.3.0", "eslint-config-prettier": "8.3.0", diff --git a/src/utils/config.ts b/src/utils/config.ts index dd257d7c3..7197dbfc6 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,8 +1,4 @@ -import { stableHash } from './hash' -import { initCache } from './cache' -import { preset } from './web-preset' -import { slowConnection } from './env' -import { +import type { PublicConfiguration, FullConfiguration, RevalidatorOptions, @@ -10,6 +6,10 @@ import { ScopedMutator, Cache } from '../types' +import { stableHash } from './hash' +import { initCache } from './cache' +import { preset } from './web-preset' +import { slowConnection } from './env' import { isUndefined, noop, mergeObjects } from './helper' // error retry diff --git a/test/use-swr-infinite.test.tsx b/test/use-swr-infinite.test.tsx index 841bff651..5cf0541cd 100644 --- a/test/use-swr-infinite.test.tsx +++ b/test/use-swr-infinite.test.tsx @@ -15,18 +15,58 @@ describe('useSWRInfinite', () => { it('should render the first page component', async () => { const key = createKey() function Page() { - const { data } = useSWRInfinite( + const { data, error, isValidating } = useSWRInfinite( index => `page-${index}-${key}`, infiniteKey => createResponse(infiniteKey) ) - return
data:{data}
+ return ( +
+
data:{data}
+
error:{error}
+
isValidating:{isValidating.toString()}
+
+ ) } renderWithConfig() screen.getByText('data:') await screen.findByText(`data:page-0-${key}`) + await screen.findByText(`error:`) + await screen.findByText(`isValidating:false`) + }) + + it('should not render anything if getKey throw error and call mutate wont cause error', async () => { + function Page() { + const { data, error, isValidating, mutate } = useSWRInfinite( + () => { + throw new Error('error') + }, + infiniteKey => createResponse(infiniteKey) + ) + + return ( +
+
mutate()}>data:{data}
+
error:{error}
+
isValidating:{isValidating.toString()}
+
+ ) + } + + renderWithConfig() + screen.getByText('data:') + + await screen.findByText(`data:`) + await screen.findByText(`error:`) + await screen.findByText(`isValidating:false`) + + fireEvent.click(screen.getByText('data:')) + + await screen.findByText(`data:`) + await screen.findByText(`error:`) + await screen.findByText(`isValidating:false`) }) it('should render the multiple pages', async () => { @@ -773,6 +813,39 @@ describe('useSWRInfinite', () => { expect(loggedValues).toEqual([1]) }) + it('setSize should only accept number', async () => { + const key = createKey() + function Comp() { + const { data, size, setSize } = useSWRInfinite( + index => [key, index], + (_, index) => createResponse(`page ${index}`) + ) + + return ( + <> +
{ + // load next page + // @ts-ignore + setSize('2') + }} + > + data:{data} +
+
size:{size}
+ + ) + } + renderWithConfig() + await screen.findByText('data:page 0') + await screen.findByText('size:1') + + fireEvent.click(screen.getByText('data:page 0')) + + await screen.findByText('data:page 0') + await screen.findByText('size:1') + }) + it('should correctly set size when setSize receives a callback', async () => { const key = createKey() diff --git a/test/use-swr-key.test.tsx b/test/use-swr-key.test.tsx index 208612444..19f95d4f6 100644 --- a/test/use-swr-key.test.tsx +++ b/test/use-swr-key.test.tsx @@ -141,6 +141,23 @@ describe('useSWR - key', () => { await screen.findByText(`${baseKey}-second`) }) + it('should not fetch if the function key throws an error', async () => { + let value = 0 + const fetcher = jest.fn(() => value++) + const key = () => { + throw new Error('error') + } + + function Page() { + const { data } = useSWR(key, fetcher) + return
{`key-${data}`}
+ } + + renderWithConfig() + await screen.findByText(`key-undefined`) + expect(fetcher).toBeCalledTimes(0) + }) + it('should cleanup state when key turns to empty', async () => { const key = createKey() function Page() { diff --git a/test/use-swr-local-mutation.test.tsx b/test/use-swr-local-mutation.test.tsx index 81b5ce419..959751f32 100644 --- a/test/use-swr-local-mutation.test.tsx +++ b/test/use-swr-local-mutation.test.tsx @@ -323,6 +323,18 @@ describe('useSWR - local mutation', () => { ).rejects.toBeInstanceOf(Error) }) + it('globalMutate should return undefined if the key is serialized to "" ', async () => { + // returns the data if promise resolved + expect(globalMutate(null, Promise.resolve('data'))).resolves.toBe(undefined) + + // throw the error if promise rejected + expect( + globalMutate(() => { + throw new Error('error') + }, Promise.resolve('data')) + ).resolves.toBe(undefined) + }) + it('should get bound mutate from useSWR', async () => { const key = createKey() function Page() { @@ -922,4 +934,52 @@ describe('useSWR - local mutation', () => { 'async3' ]) }) + + it('should ignore in flight mutation error when calling another async mutate', async () => { + const key = createKey() + const errorMutate = () => + new Promise((_, reject) => { + setTimeout(() => reject('error'), 200) + }) + + const successMutate = () => + new Promise(resolve => { + setTimeout(() => resolve('success'), 100) + }) + function Page() { + const { data, mutate: boundMutate } = useSWR(key, () => + createResponse('data', { delay: 100 }) + ) + return ( +
+
{data}
+ + +
+ ) + } + renderWithConfig() + await screen.findByText('data') + + fireEvent.click(screen.getByText('error-mutate')) + await sleep(50) + + fireEvent.click(screen.getByText('success-mutate')) + await screen.findByText('success') + + await sleep(300) + await screen.findByText('success') + }) }) diff --git a/yarn.lock b/yarn.lock index f84d8df16..ca62b6ebd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1593,13 +1593,13 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz#05e711a2e7b68342661fde61bccbd1531c19521a" - integrity sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg== +"@typescript-eslint/eslint-plugin@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.0.tgz#52cd9305ceef98a5333f9492d519e6c6c7fe7d43" + integrity sha512-spu1UW7QuBn0nJ6+psnfCc3iVoQAifjKORgBngKOmC8U/1tbe2YJMzYQqDGYB4JCss7L8+RM2kKLb1B1Aw9BNA== dependencies: - "@typescript-eslint/experimental-utils" "5.4.0" - "@typescript-eslint/scope-manager" "5.4.0" + "@typescript-eslint/experimental-utils" "5.8.0" + "@typescript-eslint/scope-manager" "5.8.0" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -1607,7 +1607,19 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@5.4.0", "@typescript-eslint/experimental-utils@^5.0.0": +"@typescript-eslint/experimental-utils@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.0.tgz#0916ffe98d34b3c95e3652efa0cace61a7b25728" + integrity sha512-KN5FvNH71bhZ8fKtL+lhW7bjm7cxs1nt+hrDZWIqb6ViCffQcWyLunGrgvISgkRojIDcXIsH+xlFfI4RCDA0xA== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.8.0" + "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/typescript-estree" "5.8.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/experimental-utils@^5.0.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz#238a7418d2da3b24874ba35385eb21cc61d2a65e" integrity sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg== @@ -1619,14 +1631,14 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/parser@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.4.0.tgz#3aa83ce349d66e39b84151f6d5464928044ca9e3" - integrity sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw== +"@typescript-eslint/parser@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.8.0.tgz#b39970b21c1d7bc4a6018507fb29b380328d2587" + integrity sha512-Gleacp/ZhRtJRYs5/T8KQR3pAQjQI89Dn/k+OzyCKOsLiZH2/Vh60cFBTnFsHNI6WAD+lNUo/xGZ4NeA5u0Ipw== dependencies: - "@typescript-eslint/scope-manager" "5.4.0" - "@typescript-eslint/types" "5.4.0" - "@typescript-eslint/typescript-estree" "5.4.0" + "@typescript-eslint/scope-manager" "5.8.0" + "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/typescript-estree" "5.8.0" debug "^4.3.2" "@typescript-eslint/scope-manager@5.4.0": @@ -1637,11 +1649,24 @@ "@typescript-eslint/types" "5.4.0" "@typescript-eslint/visitor-keys" "5.4.0" +"@typescript-eslint/scope-manager@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.8.0.tgz#2371095b4fa4c7be6a80b380f4e1b49c715e16f4" + integrity sha512-x82CYJsLOjPCDuFFEbS6e7K1QEWj7u5Wk1alw8A+gnJiYwNnDJk0ib6PCegbaPMjrfBvFKa7SxE3EOnnIQz2Gg== + dependencies: + "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/visitor-keys" "5.8.0" + "@typescript-eslint/types@5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.4.0.tgz#b1c130f4b381b77bec19696c6e3366f9781ce8f2" integrity sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA== +"@typescript-eslint/types@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.8.0.tgz#e7fa74ec35d9dbe3560d039d3d8734986c3971e0" + integrity sha512-LdCYOqeqZWqCMOmwFnum6YfW9F3nKuxJiR84CdIRN5nfHJ7gyvGpXWqL/AaW0k3Po0+wm93ARAsOdzlZDPCcXg== + "@typescript-eslint/typescript-estree@5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz#fe524fb308973c68ebeb7428f3b64499a6ba5fc0" @@ -1655,6 +1680,19 @@ semver "^7.3.5" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.0.tgz#900469ba9d5a37f4482b014ecce4a5dbb86cb4dd" + integrity sha512-srfeZ3URdEcUsSLbkOFqS7WoxOqn8JNil2NSLO9O+I2/Uyc85+UlfpEvQHIpj5dVts7KKOZnftoJD/Fdv0L7nQ== + dependencies: + "@typescript-eslint/types" "5.8.0" + "@typescript-eslint/visitor-keys" "5.8.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/visitor-keys@5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz#09bc28efd3621f292fe88c86eef3bf4893364c8c" @@ -1663,6 +1701,14 @@ "@typescript-eslint/types" "5.4.0" eslint-visitor-keys "^3.0.0" +"@typescript-eslint/visitor-keys@5.8.0": + version "5.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.0.tgz#22d4ed96fe2451135299239feedb9fe1dcec780c" + integrity sha512-+HDIGOEMnqbxdAHegxvnOqESUH6RWFRR2b8qxP1W9CZnnYh4Usz6MBL+2KMAgPk/P0o9c1HqnYtwzVH6GTIqug== + dependencies: + "@typescript-eslint/types" "5.8.0" + eslint-visitor-keys "^3.0.0" + abab@^2.0.3, abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"