Skip to content

Commit

Permalink
fix: If newData is deeply to the latest state, broadcast the latest…
Browse files Browse the repository at this point in the history
… state (#1697)
  • Loading branch information
icyJoseph authored Dec 9, 2021
1 parent ba110c3 commit 1146d52
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/use-swr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,12 @@ export const useSWRHandler = <Data = any, Error = any>(
// For local state, compare and assign.
if (!compare(stateRef.current.data, newData)) {
newState.data = newData
} else {
// data and newData are deeply equal
// it should be safe to broadcast the stale data
newState.data = stateRef.current.data
// At the end of this function, `brocastState` invokes the `onStateUpdate` function,
// which takes care of avoiding the re-render
}

// For global state, it's possible that the key has changed.
Expand Down
47 changes: 46 additions & 1 deletion test/use-swr-loading.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { act, screen, fireEvent } from '@testing-library/react'
import React from 'react'
import React, { useEffect } from 'react'
import useSWR from 'swr'
import {
createResponse,
Expand Down Expand Up @@ -77,6 +77,51 @@ describe('useSWR - loading', () => {
expect(dataLoaded).toEqual(true)
})

it('should avoid extra rerenders is the data is the `same`', async () => {
let renderCount = 0,
initialDataLoaded = false,
mutationDataLoaded = false

const key = createKey()
function Page() {
const { data, mutate } = useSWR(
key,
async () => {
const res = await createResponse({ greeting: 'hello' })
initialDataLoaded = true
return res
},
{ fallbackData: { greeting: 'hello' } }
)

useEffect(() => {
const timeout = setTimeout(
() =>
mutate(async () => {
const res = await createResponse({ greeting: 'hello' })
mutationDataLoaded = true
return res
}),
200
)

return () => clearTimeout(timeout)
}, [mutate])

renderCount++
return <div>{data?.greeting}</div>
}

renderWithConfig(<Page />)
screen.getByText('hello')

await act(() => sleep(1000)) // wait
// it doesn't re-render, but fetch was triggered
expect(initialDataLoaded).toEqual(true)
expect(mutationDataLoaded).toEqual(true)
expect(renderCount).toEqual(1)
})

it('should return enumerable object', async () => {
// If the returned object is enumerable, we can use the spread operator
// to deconstruct all the keys.
Expand Down

0 comments on commit 1146d52

Please sign in to comment.