Skip to content

Commit

Permalink
fix: mutate args for useSWRInfinite hook (#1947)
Browse files Browse the repository at this point in the history
* fix: mutate args for useSWRInfinite hook

* Add swr infinite test for revalidation with arguments

* Add swr infinite test for non-revalidation with arguments

* Rename swr infinite mutate test case

* Update type for infite mutate args

* Include 'MutatorOptions' import

Co-authored-by: sanjeev40 <sanjeev@worknetwork.in>
  • Loading branch information
sanjeev29 and sanjeev40 committed May 14, 2022
1 parent 3cd796b commit d81aa78
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 21 deletions.
1 change: 0 additions & 1 deletion _internal/utils/env.ts
@@ -1,7 +1,6 @@
import React, { useEffect, useLayoutEffect } from 'react'
import { hasRequestAnimationFrame, isWindowDefined } from './helper'


export const IS_REACT_LEGACY = !React.useId

export const IS_SERVER = !isWindowDefined || 'Deno' in window
Expand Down
12 changes: 9 additions & 3 deletions infinite/index.ts
Expand Up @@ -15,7 +15,8 @@ import {
BareFetcher,
useIsomorphicLayoutEffect,
serialize,
withMiddleware
withMiddleware,
MutatorOptions
} from 'swr/_internal'

import type {
Expand Down Expand Up @@ -197,13 +198,18 @@ export const infinite = (<Data, Error>(useSWRNext: SWRHook) =>
| [undefined | Data[] | Promise<Data[]> | MutatorCallback<Data[]>]
| [
undefined | Data[] | Promise<Data[]> | MutatorCallback<Data[]>,
boolean
undefined | boolean | MutatorOptions<Data>
]
) => {
const data = args[0]

// When passing as a boolean, it's explicitly used to disable/enable
// revalidation.
const options =
typeof args[1] === 'boolean' ? { revalidate: args[1] } : args[1] || {}

// Default to true.
const shouldRevalidate = args[1] !== false
const shouldRevalidate = options.revalidate !== false

// It is possible that the key is still falsy.
if (!infiniteKey) return
Expand Down
8 changes: 6 additions & 2 deletions test/use-swr-config-callbacks.test.tsx
Expand Up @@ -57,7 +57,9 @@ describe('useSWR - config callbacks', () => {
)
return (
<div onClick={() => mutate()}>
<>hello, {data}, {props.text}</>
<>
hello, {data}, {props.text}
</>
</div>
)
}
Expand Down Expand Up @@ -100,7 +102,9 @@ describe('useSWR - config callbacks', () => {
if (error) return <div title={props.text}>{error.message}</div>
return (
<div>
<>hello, {data}, {props.text}</>
<>
hello, {data}, {props.text}
</>
</div>
)
}
Expand Down
60 changes: 50 additions & 10 deletions test/use-swr-error.test.tsx
Expand Up @@ -17,7 +17,11 @@ describe('useSWR - error', () => {
createResponse(new Error('error!'))
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}

renderWithConfig(<Page />)
Expand All @@ -37,7 +41,11 @@ describe('useSWR - error', () => {
{ onError: (_, errorKey) => (erroredSWR = errorKey) }
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}

renderWithConfig(<Page />)
Expand All @@ -63,7 +71,11 @@ describe('useSWR - error', () => {
}
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}
renderWithConfig(<Page />)
screen.getByText('hello,')
Expand Down Expand Up @@ -93,7 +105,11 @@ describe('useSWR - error', () => {
}
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}
renderWithConfig(<Page />)
screen.getByText('hello,')
Expand Down Expand Up @@ -130,7 +146,11 @@ describe('useSWR - error', () => {
}
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}
renderWithConfig(<Page />)
screen.getByText('hello,')
Expand Down Expand Up @@ -158,7 +178,11 @@ describe('useSWR - error', () => {
}
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}
renderWithConfig(<Page />)
screen.getByText('hello,')
Expand Down Expand Up @@ -186,7 +210,11 @@ describe('useSWR - error', () => {
}
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}
renderWithConfig(<Page />)
screen.getByText('hello,')
Expand Down Expand Up @@ -241,7 +269,11 @@ describe('useSWR - error', () => {
}
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}

renderWithConfig(<Page />)
Expand Down Expand Up @@ -307,7 +339,11 @@ describe('useSWR - error', () => {
},
dedupingInterval: 0
})
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}

function App() {
Expand Down Expand Up @@ -344,7 +380,11 @@ describe('useSWR - error', () => {
}
)
if (error) return <div>{error.message}</div>
return <div><>hello, {data}</></div>
return (
<div>
<>hello, {data}</>
</div>
)
}

renderWithConfig(<Page />)
Expand Down
67 changes: 66 additions & 1 deletion test/use-swr-infinite.test.tsx
Expand Up @@ -1183,7 +1183,7 @@ describe('useSWRInfinite', () => {
await screen.findByText('data: B1,B2,B3')
})

it('should revalidate when the component is mounted and revalidateOnMount is enabled', async () => {
it('should revalidate the resource with bound mutate when arguments are passed', async () => {
const key = createKey()

let counter = 0
Expand Down Expand Up @@ -1223,6 +1223,71 @@ describe('useSWRInfinite', () => {
await screen.findByText('data: 2')
})

// https://github.com/vercel/swr/issues/1899
it('should revalidate the resource with bound mutate when options is of Object type ', async () => {
let t = 0
const key = createKey()
const fetcher = jest.fn(async () =>
createResponse(`foo-${t++}`, { delay: 10 })
)
const logger = []
function Page() {
const { data, mutate } = useSWRInfinite(() => key, fetcher, {
dedupingInterval: 0
})
logger.push(data)
return (
<>
<div>data: {String(data)}</div>
<button onClick={() => mutate(data, { revalidate: true })}>
mutate
</button>
</>
)
}

renderWithConfig(<Page />)
await screen.findByText('data: foo-0')

fireEvent.click(screen.getByText('mutate'))
await screen.findByText('data: foo-1')
expect(fetcher).toBeCalledTimes(2)

expect(logger).toEqual([undefined, ['foo-0'], ['foo-1']])
})

// https://github.com/vercel/swr/issues/1899
it('should not revalidate the resource with bound mutate when options is of Object type', async () => {
let t = 0
const key = createKey()
const fetcher = jest.fn(async () =>
createResponse(`foo-${t++}`, { delay: 10 })
)
const logger = []
function Page() {
const { data, mutate } = useSWRInfinite(() => key, fetcher, {
dedupingInterval: 0
})
logger.push(data)
return (
<>
<div>data: {String(data)}</div>
<button onClick={() => mutate(data, { revalidate: false })}>
mutate
</button>
</>
)
}

renderWithConfig(<Page />)
await screen.findByText('data: foo-0')

fireEvent.click(screen.getByText('mutate'))
expect(fetcher).toBeCalledTimes(1)

expect(logger).toEqual([undefined, ['foo-0']])
})

it('should share data with useSWR', async () => {
const key = createKey()
const SWR = () => {
Expand Down
14 changes: 10 additions & 4 deletions test/use-swr-suspense.test.tsx
Expand Up @@ -16,7 +16,9 @@ import {
sleep
} from './utils'

class ErrorBoundary extends React.Component<PropsWithChildren<{ fallback: ReactNode }>> {
class ErrorBoundary extends React.Component<
PropsWithChildren<{ fallback: ReactNode }>
> {
state = { hasError: false }
static getDerivedStateFromError() {
return {
Expand Down Expand Up @@ -112,9 +114,13 @@ describe('useSWR - suspense', () => {
jest.spyOn(console, 'error').mockImplementation(() => {})
const key = createKey()
function Section() {
const { data } = useSWR<any>(key, () => createResponse(new Error('error')), {
suspense: true
})
const { data } = useSWR<any>(
key,
() => createResponse(new Error('error')),
{
suspense: true
}
)
return <div>{data}</div>
}

Expand Down

0 comments on commit d81aa78

Please sign in to comment.