Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: mutate args for useSWRInfinite hook #1947

Merged
merged 8 commits into from May 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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