99import { Builder } from './extraReducersBuilder' ;
1010import { listenerMiddleware } from './middleware' ;
1111import Settings from './settings' ;
12- import { REHYDRATE } from './types' ;
1312import UpdatedAtHelper from './updatedAtHelper' ;
14- import { writePersistedStorage } from './utils' ;
13+ import { REHYDRATE , writePersistedStorage } from './utils' ;
1514
1615/**
1716 * A wrapper around the standard RTK `createSlice()` function that adds
@@ -58,14 +57,38 @@ export const createPersistedSlice: <
5857 PeristedSelectors
5958 > ,
6059) => {
61- // Subscribe the slice to be persisted
60+ /**
61+ * Registers the slice's name to the list of persisted slices.
62+ * This allows the persistence logic to identify which parts of the state to manage.
63+ */
6264 Settings . subscribeSlice ( sliceOptions . name ) ;
65+
6366 /**
6467 * A flag to ensure the rehydration process runs only once per slice.
6568 * @internal
6669 */
6770 let isHydrated = false ;
6871
72+ /**
73+ * A timeout variable to manage the debouncing of the storage write.
74+ * @internal
75+ */
76+ let debounceTimeout : NodeJS . Timeout | null = null ;
77+
78+ /**
79+ * Debounces the `writePersistedStorage` function to prevent excessive writes
80+ * during rapid state changes. The state is saved 100ms after the last change.
81+ * @param state - The current root state of the Redux store.
82+ * @param name - The name of the slice to persist.
83+ * @internal
84+ */
85+ const onDump = ( state : Record < Name , SliceState > , name : Name ) => {
86+ if ( debounceTimeout ) clearTimeout ( debounceTimeout ) ;
87+ debounceTimeout = setTimeout ( ( ) => {
88+ writePersistedStorage ( state , name ) ;
89+ } , 100 ) ;
90+ } ;
91+
6992 /**
7093 * Creates a typed instance of the listener middleware's startListening function.
7194 * @internal
@@ -106,7 +129,7 @@ export const createPersistedSlice: <
106129 effect : ( _action , { getState } ) => {
107130 if ( Settings . isPersistenceEnabled ) {
108131 const state = getState ( ) ;
109- writePersistedStorage ( state , sliceOptions . name ) ;
132+ onDump ( state , sliceOptions . name ) ;
110133 }
111134 } ,
112135 } ) ;
@@ -120,13 +143,13 @@ export const createPersistedSlice: <
120143 startAppListening ( {
121144 predicate : ( action ) => {
122145 // Exclude the slice's own actions (already handled) and the rehydrate action.
123- if ( action . type === REHYDRATE . toString ( ) || action . type . startsWith ( `${ slice . name } /` ) ) return false ;
146+ if ( action . type === REHYDRATE . toString ( ) || action . type . startsWith ( `${ slice . name } /` ) || ! Settings . isPersistenceEnabled ) return false ;
124147 return true ;
125148 } ,
126149 effect : async ( _action , { getState } ) => {
127- if ( ! await UpdatedAtHelper . shouldSave ( sliceOptions . name ) || ! Settings . isPersistenceEnabled ) return ;
150+ if ( ! await UpdatedAtHelper . shouldSave ( sliceOptions . name ) ) return ;
128151 const state = getState ( ) ;
129- writePersistedStorage ( state , sliceOptions . name ) ;
152+ onDump ( state , sliceOptions . name ) ;
130153 } ,
131154 } ) ;
132155
0 commit comments