Skip to content

Commit

Permalink
fix mutate
Browse files Browse the repository at this point in the history
close vercel#1070; close vercel#1074;
  • Loading branch information
promer94 committed Mar 28, 2021
1 parent 628ed71 commit 536e25e
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 6 deletions.
8 changes: 2 additions & 6 deletions src/use-swr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ async function mutate<Data = any>(

// track timestamps before await asynchronously
const beforeMutationTs = MUTATION_TS[key]
const beforeConcurrentPromisesTs = CONCURRENT_PROMISES_TS[key]

let data: any, error: unknown
let isAsyncMutation = false
Expand Down Expand Up @@ -142,10 +141,7 @@ async function mutate<Data = any>(

const shouldAbort = (): boolean | void => {
// check if other mutations have occurred since we've started this mutation
if (
beforeMutationTs !== MUTATION_TS[key] ||
beforeConcurrentPromisesTs !== CONCURRENT_PROMISES_TS[key]
) {
if (beforeMutationTs !== MUTATION_TS[key]) {
if (error) throw error
return true
}
Expand Down Expand Up @@ -389,7 +385,7 @@ function useSWR<Data = any, Error = any>(
// we have to ignore the revalidation result (res) because it's no longer fresh.
// meanwhile, a new revalidation should be triggered when the mutation ends.
if (
MUTATION_TS[key] &&
MUTATION_TS[key] !== undefined &&
// case 1
(startAt <= MUTATION_TS[key] ||
// case 2
Expand Down
137 changes: 137 additions & 0 deletions test/use-swr-local-mutation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -506,4 +506,141 @@ describe('useSWR - local mutation', () => {
expect(mutationRecivedValues).toEqual([0, 1])
expect(renderRecivedValues).toEqual([undefined, 0, 1, 2])
})

it('async mutation case 1 (startAt <= MUTATION_TS[key])', async () => {
let result = 0
const fetcher = jest.fn(createResponse)
function Component() {
const { data, mutate: boundMutate } = useSWR(
'mutate-7',
() =>
fetcher(0, {
delay: 300
}),
{
dedupingInterval: 200
}
)
return (
<div
onClick={() => {
boundMutate(async () => {
result += 1
return createResponse(result, {
delay: 100
})
}, false)
}}
>
{data !== undefined ? `data: ${data.toString()}` : 'loading'}
</div>
)
}

render(<Component />)
screen.getByText('loading')

await act(() => sleep(50))

fireEvent.click(screen.getByText('loading'))

await act(() => sleep(100))
// mutate success
await screen.findByText('data: 1')

await act(() => sleep(150))
// fetcher result should be ignored
expect(fetcher).toBeCalledTimes(1)
await screen.findByText('data: 1')
})

it('async mutation case 2 (startAt <= MUTATION_END_TS[key])', async () => {
let result = 0
const fetcher = jest.fn(createResponse)
function Component() {
const [key, setKey] = useState(null)
const { data } = useSWR(
key,
() =>
fetcher(0, {
delay: 400
}),
{
dedupingInterval: 200
}
)
useEffect(() => {
mutate(
'mutate-8',
async () => {
result += 1
return createResponse(result, {
delay: 200
})
},
false
)
setKey('mutate-8')
}, [])
return (
<div>{data !== undefined ? `data: ${data.toString()}` : 'loading'}</div>
)
}

render(<Component />)
screen.getByText('loading')

// mutate success
await act(() => sleep(200))
fireEvent.click(screen.getByText('data: 1'))

// fetcher result should be ignored
await act(() => sleep(200))
expect(fetcher).toBeCalledTimes(1)
await screen.findByText('data: 1')
})

it('async mutation case 3 (MUTATION_END_TS[key] === 0)', async () => {
let result = 0
const fetcher = jest.fn(createResponse)
function Component() {
const [key, setKey] = useState(null)
const { data } = useSWR(
key,
() =>
fetcher(0, {
delay: 100
}),
{
dedupingInterval: 200
}
)
useEffect(() => {
setKey('mutate-9')
mutate(
'mutate-9',
async () => {
result += 1
return createResponse(result, { delay: 200 })
},
false
)
}, [])
return (
<div>{data !== undefined ? `data: ${data.toString()}` : 'loading'}</div>
)
}

render(<Component />)
screen.getByText('loading')

// fetcher result should be ignored
await act(() => sleep(100))
expect(fetcher).toBeCalledTimes(1)
screen.getByText('loading')

// mutate success
await act(() => sleep(100))
await screen.findByText('data: 1')
})
})

0 comments on commit 536e25e

Please sign in to comment.