Skip to content

Commit

Permalink
Micro optimizations (#1018)
Browse files Browse the repository at this point in the history
* code refactoring

* update rerender

* code refactoring

* code refactoring

* Update cache.ts

* make tests more stable
  • Loading branch information
shuding committed Mar 13, 2021
1 parent 6f03890 commit b18414b
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 46 deletions.
30 changes: 15 additions & 15 deletions src/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,42 @@ import { Cache as CacheType, Key, CacheListener } from './types'
import hash from './libs/hash'

export default class Cache implements CacheType {
private __cache: Map<string, any>
private __listeners: CacheListener[]
private cache: Map<string, any>
private subs: CacheListener[]

constructor(initialData: any = {}) {
this.__cache = new Map(Object.entries(initialData))
this.__listeners = []
this.cache = new Map(Object.entries(initialData))
this.subs = []
}

get(key: Key): any {
const [_key] = this.serializeKey(key)
return this.__cache.get(_key)
return this.cache.get(_key)
}

set(key: Key, value: any): any {
const [_key] = this.serializeKey(key)
this.__cache.set(_key, value)
this.cache.set(_key, value)
this.notify()
}

keys() {
return Array.from(this.__cache.keys())
return Array.from(this.cache.keys())
}

has(key: Key) {
const [_key] = this.serializeKey(key)
return this.__cache.has(_key)
return this.cache.has(_key)
}

clear() {
this.__cache.clear()
this.cache.clear()
this.notify()
}

delete(key: Key) {
const [_key] = this.serializeKey(key)
this.__cache.delete(_key)
this.cache.delete(_key)
this.notify()
}

Expand Down Expand Up @@ -74,22 +74,22 @@ export default class Cache implements CacheType {
}

let isSubscribed = true
this.__listeners.push(listener)
this.subs.push(listener)

return () => {
if (!isSubscribed) return
isSubscribed = false
const index = this.__listeners.indexOf(listener)
const index = this.subs.indexOf(listener)
if (index > -1) {
this.__listeners[index] = this.__listeners[this.__listeners.length - 1]
this.__listeners.length--
this.subs[index] = this.subs[this.subs.length - 1]
this.subs.length--
}
}
}

// Notify Cache subscribers about a change in the cache
private notify() {
for (let listener of this.__listeners) {
for (let listener of this.subs) {
listener()
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/use-swr-infinite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,20 @@ function useSWRInfinite<Data = any, Error = any>(
// not ready
}

const [, rerender] = useState<boolean>(false)
const rerender = useState({})[1]

// we use cache to pass extra info (context) to fetcher so it can be globally shared
// here we get the key of the fetcher context cache
let contextCacheKey: string | null = null
if (firstPageKey) {
contextCacheKey = 'context@' + firstPageKey
contextCacheKey = 'ctx@' + firstPageKey
}

// page count is cached as well, so when navigating the list can be restored
let pageCountCacheKey: string | null = null
let cachedPageSize
if (firstPageKey) {
pageCountCacheKey = 'size@' + firstPageKey
pageCountCacheKey = 'len@' + firstPageKey
cachedPageSize = cache.get(pageCountCacheKey)
}
const pageCountRef = useRef<number>(cachedPageSize || initialSize)
Expand All @@ -105,10 +105,10 @@ function useSWRInfinite<Data = any, Error = any>(

// actual swr of all pages
const swr = useSWR<Data[], Error>(
firstPageKey ? ['many', firstPageKey] : null,
firstPageKey ? ['inf', firstPageKey] : null,
async () => {
// get the revalidate context
const { originalData, force } = cache.get(contextCacheKey) || {}
const { data: originalData, force } = cache.get(contextCacheKey) || {}

// return an array of page data
const data: Data[] = []
Expand Down Expand Up @@ -174,7 +174,7 @@ function useSWRInfinite<Data = any, Error = any>(
if (shouldRevalidate && typeof data !== 'undefined') {
// we only revalidate the pages that are changed
const originalData = dataRef.current
cache.set(contextCacheKey, { originalData, force: false })
cache.set(contextCacheKey, { data: originalData, force: false })
} else if (shouldRevalidate) {
// calling `mutate()`, we revalidate all pages
cache.set(contextCacheKey, { force: true })
Expand All @@ -197,7 +197,7 @@ function useSWRInfinite<Data = any, Error = any>(
pageCountRef.current = arg
}
cache.set(pageCountCacheKey, pageCountRef.current)
rerender(v => !v)
rerender({})
return mutate(v => v)
},
[mutate, pageCountCacheKey]
Expand Down
40 changes: 17 additions & 23 deletions src/use-swr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ function useSWR<Data = any, Error = any>(
// display the data label in the React DevTools next to SWR hooks
useDebugValue(stateRef.current.data)

const rerender = useState<unknown>(null)[1]
const rerender = useState<unknown>({})[1]

let dispatch = useCallback(
(payload: Action<Data, Error>) => {
Expand Down Expand Up @@ -352,26 +352,21 @@ function useSWR<Data = any, Error = any>(
revalidators: Record<string, Revalidator[]>,
callback: Revalidator
) => {
if (!callback) return
if (!revalidators[key]) {
revalidators[key] = [callback]
} else {
revalidators[key].push(callback)
}
}

const removeRevalidator = (
revlidators: Record<string, Revalidator[]>,
callback: Revalidator
) => {
if (revlidators[key]) {
const revalidators = revlidators[key]
const index = revalidators.indexOf(callback)
return () => {
const keyedRevalidators = revalidators[key]
const index = keyedRevalidators.indexOf(callback)

if (index >= 0) {
// 10x faster than splice
// https://jsperf.com/array-remove-by-index
revalidators[index] = revalidators[revalidators.length - 1]
revalidators.pop()
// O(1): faster than splice
keyedRevalidators[index] =
keyedRevalidators[keyedRevalidators.length - 1]
keyedRevalidators.pop()
}
}
}
Expand Down Expand Up @@ -573,9 +568,8 @@ function useSWR<Data = any, Error = any>(
const latestKeyedData = resolveData()

// update the state if the key changed (not the inital render) or cache updated
if (keyRef.current !== key) {
keyRef.current = key
}
keyRef.current = key

if (!config.compare(currentHookData, latestKeyedData)) {
dispatch({ data: latestKeyedData })
}
Expand Down Expand Up @@ -665,9 +659,9 @@ function useSWR<Data = any, Error = any>(
return false
}

addRevalidator(FOCUS_REVALIDATORS, onFocus)
addRevalidator(RECONNECT_REVALIDATORS, onReconnect)
addRevalidator(CACHE_REVALIDATORS, onUpdate)
const unsubFocus = addRevalidator(FOCUS_REVALIDATORS, onFocus)
const unsubReconnect = addRevalidator(RECONNECT_REVALIDATORS, onReconnect)
const unsubUpdate = addRevalidator(CACHE_REVALIDATORS, onUpdate)

return () => {
// cleanup
Expand All @@ -676,9 +670,9 @@ function useSWR<Data = any, Error = any>(
// mark it as unmounted
unmountedRef.current = true

removeRevalidator(FOCUS_REVALIDATORS, onFocus)
removeRevalidator(RECONNECT_REVALIDATORS, onReconnect)
removeRevalidator(CACHE_REVALIDATORS, onUpdate)
unsubFocus()
unsubReconnect()
unsubUpdate()
}
}, [key, revalidate])

Expand Down
2 changes: 1 addition & 1 deletion test/use-swr-configs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { sleep } from './utils'
describe('useSWR - configs', () => {
it('should read the config fallback from the context', async () => {
let value = 0
const INTERVAL = 10
const INTERVAL = 50
const fetcher = () => value++

function Section() {
Expand Down

0 comments on commit b18414b

Please sign in to comment.