diff --git a/packages/toolkit/src/persistor/index.ts b/packages/toolkit/src/persistor/index.ts index baf29aff22..b2cec08f26 100644 --- a/packages/toolkit/src/persistor/index.ts +++ b/packages/toolkit/src/persistor/index.ts @@ -11,6 +11,8 @@ import { createSlice, nanoid, SHOULD_AUTOBATCH, + combineSlices, + configureStore, } from '@reduxjs/toolkit' import { promiseTry } from '../utils' @@ -48,6 +50,7 @@ interface PersistConfig { storage: PersistStorage serialize?: ((state: State) => Serialized) | false deserialize?: ((serialized: Serialized) => State) | false + merge?: (current: State | undefined, hydrated: State) => State } interface PersistRegistryEntry { @@ -175,13 +178,9 @@ export const createPersistor = ({ const result = next(action) const stateAfter = getState() if (stateBefore !== stateAfter) { - Object.entries(internalRegistry).forEach(async ([name, entry]) => { - try { - await storeState(name, stateAfter, entry) - } catch (e) { - onError?.(e) - } - }) + Object.entries(internalRegistry).forEach(([name, entry]) => + storeState(name, stateAfter, entry).catch(onError) + ) } return result } @@ -197,28 +196,33 @@ export const createPersistor = ({ return store } - const persistSlice = ( - { - name, - reducer, - }: { - name: string - reducer: Reducer - }, - config: PersistConfig - ): Reducer => { + const persistSlice = < + Slice extends { name: string; reducer: Reducer }, + SS + >( + { reducer, name, ...slice }: Slice, + config: PersistConfig< + Slice extends { reducer: Reducer } ? State : never, + SS + > + ): Slice => { + const { merge = (_, hydrated) => hydrated } = config internalRegistry[name] = { config } - return (state, action) => { - let nextState = state - if (hydrate.match(action) && action.payload.name === name) { - const possibleState = action.payload.state - nextState = reducer(possibleState || state, action) - } else { - nextState = reducer(state, action) - } - return nextState - } + return { + ...slice, + name, + reducer(state, action) { + let nextState = state + if (hydrate.match(action) && action.payload.name === name) { + const hydrated = action.payload.state + nextState = reducer(merge(state, hydrated), action) + } else { + nextState = reducer(state, action) + } + return nextState + }, + } as Slice } return {