@stainless-code/persist
Version:
Hydration-aware persistence for any reactive store — zero-dep persistSource core; codecs, backends, cross-tab transport, source + framework hydration adapters ship as opt-in recipes
66 lines (65 loc) • 2.39 kB
JavaScript
import { l as persistSource } from "../persist-core-B5VikEft.mjs";
//#region src/adapters/sources/redux.ts
/** Private set/hydrate action — owned by this module; not for app dispatch. */
const PERSIST_SET = "@stainless-code/persist/SET";
/**
* Wrap the root reducer so hydrate/`setState` can replace state. Do not wrap
* slices inside `combineReducers` — the payload is the full root. Without this,
* RTK slices ignore the private action (silent no-op). Named to avoid clashing
* with redux-persist's `persistReducer`.
*
* @example
* ```ts
* import { createStore } from "redux";
* import { persistableReducer } from "@stainless-code/persist/sources/redux";
* const store = createStore(persistableReducer(rootReducer));
* ```
*/
function persistableReducer(baseReducer) {
return (state, action) => {
if (action.type === PERSIST_SET) return action.payload;
return baseReducer(state, action);
};
}
/**
* Persist a Redux store (classic `createStore` or RTK `configureStore`).
* Redux has no `setState` — hydrate/writes dispatch a private action handled
* by {@link persistableReducer} on the root. Do not use `replaceReducer` for
* hydrate.
*
* If you also import redux-persist's `persistStore`, alias this one:
* `import { persistStore as persistWithStainless } from "@stainless-code/persist/sources/redux"`.
*
* @example
* ```ts
* import { createStore } from "redux";
* import { createJSONStorage } from "@stainless-code/persist";
* import {
* persistStore,
* persistableReducer,
* } from "@stainless-code/persist/sources/redux";
* const store = createStore(persistableReducer(rootReducer));
* const persist = persistStore(store, {
* name: "root",
* storage: createJSONStorage(() => localStorage),
* });
* ```
*/
function persistStore(store, options) {
return persistSource({
getState: () => store.getState(),
setState: (updater) => {
const prev = store.getState();
const payload = updater(prev);
const action = {
type: PERSIST_SET,
payload
};
store.dispatch(action);
if (process.env.NODE_ENV !== "production" && store.getState() === prev) console.warn("[@stainless-code/persist/sources/redux] setState/hydrate did not apply. Wrap the root reducer with persistableReducer (not each slice).");
},
subscribe: (listener) => ({ unsubscribe: store.subscribe(listener) })
}, options);
}
//#endregion
export { persistStore, persistableReducer };