|
| 1 | +// src/utils/reactStoreEnhancer.ts |
| 2 | +import { experimental } from 'react-concurrent-store' |
| 3 | +import type { StoreEnhancer } from 'redux' |
| 4 | + |
| 5 | +const { createStoreFromSource } = experimental |
| 6 | + |
| 7 | +export type Reducer<S, A> = (state: S, action: A) => S |
| 8 | + |
| 9 | +export interface ISource<S, A> { |
| 10 | + /** |
| 11 | + * Returns an immutable snapshot of the current state |
| 12 | + */ |
| 13 | + getState(): S |
| 14 | + /** |
| 15 | + * A pure function which takes and arbitrary state and an updater/action and |
| 16 | + * returns a new state. |
| 17 | + * |
| 18 | + * React needs this in order to generate temporary states. |
| 19 | + * |
| 20 | + * See: https://jordaneldredge.com/notes/react-rebasing/ |
| 21 | + */ |
| 22 | + reducer: Reducer<S, A> |
| 23 | +} |
| 24 | + |
| 25 | +export const addReactStore: StoreEnhancer<{ |
| 26 | + reactStore: ReturnType<typeof createStoreFromSource<any, any>> |
| 27 | +}> = (createStore) => { |
| 28 | + return (reducer, preloadedState) => { |
| 29 | + const store = createStore(reducer, preloadedState) |
| 30 | + |
| 31 | + // Create concurrent-safe store wrapper |
| 32 | + const reactStore = createStoreFromSource({ |
| 33 | + getState: store.getState, |
| 34 | + reducer: reducer, |
| 35 | + }) |
| 36 | + |
| 37 | + // Intercept dispatch to notify reactStore |
| 38 | + const originalDispatch = store.dispatch |
| 39 | + store.dispatch = (action: any) => { |
| 40 | + const result = originalDispatch(action) |
| 41 | + reactStore.handleUpdate(action) |
| 42 | + return result |
| 43 | + } |
| 44 | + |
| 45 | + // Attach reactStore to Redux store |
| 46 | + return Object.assign(store, { reactStore }) |
| 47 | + } |
| 48 | +} |
0 commit comments