Skip to content

Commit

Permalink
perf(app/selector): implement subscribeChange store enhancer
Browse files Browse the repository at this point in the history
  • Loading branch information
exuanbo committed Dec 8, 2023
1 parent f108fe1 commit 5299d2d
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/app/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const useSelector = <TSelected>(
equalityFn: EqualityFn<TSelected> = refEquality,
): TSelected => {
const selectedState = useSyncExternalStoreWithSelector(
store.subscribe,
store.subscribeChange,
store.getState,
selector,
equalityFn,
Expand Down
5 changes: 4 additions & 1 deletion src/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { createActionObserver } from './actionObserver'
import { loadState as loadStateFromLocalStorage } from './localStorage'
import { getInitialStateToPersist } from './persist'
import { createStateObserver } from './stateObserver'
import { subscribeChange } from './subscribeChange'
import { loadState as loadStateFromUrl } from './url'

const rootReducer = combineSlices(
Expand Down Expand Up @@ -46,6 +47,8 @@ export const store = configureStore({
preloadedState: getPreloadedState(),
enhancers: (getDefaultEnhancers) => {
const defaultEnhancers = getDefaultEnhancers()
return defaultEnhancers.concat(stateObserver.enhancer, actionObserver.enhancer)
return defaultEnhancers
.concat(stateObserver.enhancer, actionObserver.enhancer)
.concat(subscribeChange)
},
})
34 changes: 34 additions & 0 deletions src/app/subscribeChange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Store, StoreEnhancer } from '@reduxjs/toolkit'

type SubscribeChange = Store['subscribe']

export const subscribeChange: StoreEnhancer<{ subscribeChange: SubscribeChange }> =
(createStore) =>
(...args) => {
const store = createStore(...args)

let stateSnapshot: ReturnType<typeof store.getState> | null = null

const dispatch: typeof store.dispatch = (action) => {
try {
stateSnapshot = store.getState()
return store.dispatch(action)
} finally {
stateSnapshot = null
}
}

const subscribeChange: typeof store.subscribe = (listener) =>
store.subscribe(() => {
const state = store.getState()
if (state !== stateSnapshot) {
listener()
}
})

return {
...store,
dispatch,
subscribeChange,
}
}

0 comments on commit 5299d2d

Please sign in to comment.