Skip to content

Commit

Permalink
feat: Add populateCache option to mutate (vercel#1729)
Browse files Browse the repository at this point in the history
* add populateCache option to mutate

* rename type and export it
  • Loading branch information
shuding authored and nevilm-lt committed Apr 22, 2022
1 parent e108281 commit 8c137b5
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 27 deletions.
14 changes: 6 additions & 8 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,9 @@ export type MutatorCallback<Data = any> = (
currentData?: Data
) => Promise<undefined | Data> | undefined | Data

export type MutatorOptions<Data = any> = {
export type MutatorOptions = {
revalidate?: boolean
populateCache?: boolean | ((result: any, currentData: Data) => Data)
optimisticData?: Data | ((currentData?: Data) => Data)
rollbackOnError?: boolean
populateCache?: boolean
}

export type Broadcaster<Data = any, Error = any> = (
Expand All @@ -169,7 +167,7 @@ export type MutatorFn<Data = any> = (
cache: Cache,
key: Key,
data?: Data | Promise<Data> | MutatorCallback<Data>,
opts?: boolean | MutatorOptions<Data>
opts?: boolean | MutatorOptions
) => Promise<Data | undefined>

export type MutatorWrapper<Fn> = Fn extends (
Expand All @@ -191,19 +189,19 @@ export interface ScopedMutator<Data = any> {
(
key: Key,
data?: Data | Promise<Data> | MutatorCallback<Data>,
opts?: boolean | MutatorOptions<Data>
opts?: boolean | MutatorOptions
): Promise<Data | undefined>
/** This is used for global mutator */
<T = any>(
key: Key,
data?: T | Promise<T> | MutatorCallback<T>,
opts?: boolean | MutatorOptions<Data>
opts?: boolean | MutatorOptions
): Promise<T | undefined>
}

export type KeyedMutator<Data> = (
data?: Data | Promise<Data> | MutatorCallback<Data>,
opts?: boolean | MutatorOptions<Data>
opts?: boolean | MutatorOptions
) => Promise<Data | undefined>

// Public types
Expand Down
4 changes: 2 additions & 2 deletions src/utils/broadcast-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const broadcastState: Broadcaster = (
error,
isValidating,
revalidate,
broadcast = true
populateCache = true
) => {
const [EVENT_REVALIDATORS, STATE_UPDATERS, , FETCH] = SWRGlobalState.get(
cache
Expand All @@ -18,7 +18,7 @@ export const broadcastState: Broadcaster = (
const updaters = STATE_UPDATERS[key]

// Cache was populated, update states of all hooks.
if (broadcast && updaters) {
if (populateCache && updaters) {
for (let i = 0; i < updaters.length; ++i) {
updaters[i](data, error, isValidating)
}
Expand Down
22 changes: 5 additions & 17 deletions src/utils/mutate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const internalMutate = async <Data>(
Cache,
Key,
undefined | Data | Promise<Data | undefined> | MutatorCallback<Data>,
undefined | boolean | MutatorOptions<Data>
undefined | boolean | MutatorOptions
]
) => {
const [cache, _key, _data, _opts] = args
Expand All @@ -22,12 +22,8 @@ export const internalMutate = async <Data>(
typeof _opts === 'boolean' ? { revalidate: _opts } : _opts || {}

// Fallback to `true` if it's not explicitly set to `false`
let populateCache = isUndefined(options.populateCache)
? true
: options.populateCache
const revalidate = options.revalidate !== false
const rollbackOnError = options.rollbackOnError !== false
const customOptimisticData = options.optimisticData
const populateCache = options.populateCache !== false

// Serilaize key
const [key, , keyInfo] = serialize(_key)
Expand All @@ -43,9 +39,8 @@ export const internalMutate = async <Data>(
key,
cache.get(key),
UNDEFINED,
UNDEFINED,
revalidate,
true
populateCache
)
}

Expand Down Expand Up @@ -100,20 +95,13 @@ export const internalMutate = async <Data>(
}
}

// If we should write back the cache after request.
if (populateCache) {
if (!error) {
// Transform the result into data.
if (isFunction(populateCache)) {
data = populateCache(data, rollbackData)
}

// Only update cached data if there's no error. Data can be `undefined` here.
cache.set(key, data)
}

// Always update or reset the error.
cache.set(keyInfo, mergeObjects(cache.get(keyInfo), { error }))
cache.set(keyErr, error)
}

// Reset the timestamp to mark the mutation has ended.
Expand All @@ -127,7 +115,7 @@ export const internalMutate = async <Data>(
error,
UNDEFINED,
revalidate,
!!populateCache
populateCache
)

// Throw error or return data
Expand Down
29 changes: 29 additions & 0 deletions test/use-swr-local-mutation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -982,4 +982,33 @@ describe('useSWR - local mutation', () => {
await sleep(300)
await screen.findByText('success')
})

it('should not update the cache when `populateCache` is disabled', async () => {
const key = createKey()
function Page() {
const { data, mutate } = useSWR(key, () => 'foo')
return (
<>
<div>data: {String(data)}</div>
<button
onClick={() =>
mutate('bar', {
revalidate: false,
populateCache: false
})
}
>
mutate
</button>
</>
)
}

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

fireEvent.click(screen.getByText('mutate'))
await sleep(30)
await screen.findByText('data: foo')
})
})

0 comments on commit 8c137b5

Please sign in to comment.