Learn to persist Gutenberg state using Redux middleware. We’ll show you how to sync editor data to localStorage for a seamless, high-performance experience.
Previously in this course, we explored State Management with @wordpress/data: Building Scalable Stores to handle complex data flows. While that lesson focused on ephemeral runtime state, this lesson adds the layer of persistence, ensuring your plugin's block settings and UI state survive page reloads and browser sessions by syncing your store with localStorage.
In the WordPress block editor, state is often transient. When a user refreshes the page, the @wordpress/data store resets. While block attributes are saved to the database upon post update, local UI preferences—like toggle states in the sidebar or view modes in custom panels—often need to persist before the user hits "Update."
We solve this by implementing custom Redux middleware. Middleware acts as a hook into the dispatch process, allowing us to intercept every action. By filtering specific actions, we can write the current state to the browser’s localStorage asynchronously, ensuring our application remains performant while maintaining data integrity.
To persist state without dragging down the editor's performance, we avoid writing to the disk on every single action. Instead, we use a "throttle" pattern.
localStorage.In our Knowledge Base plugin, we want to persist the user's "collapsed" state for our custom block sidebar panels.
JAVASCRIPTimport { throttle } from CE9178">'lodash'; // Define the key for our plugin's persistence const STORAGE_KEY = CE9178">'kb_plugin_ui_state'; // Throttle the storage update to once every 2 seconds const persistState = throttle((state) => { try { const serializedState = JSON.stringify(state); window.localStorage.setItem(STORAGE_KEY, serializedState); } catch (err) { console.error(CE9178">'Could not save state to localStorage', err); } }, 2000); export const persistenceMiddleware = (store) => (next) => (action) => { const result = next(action); // Only persist on specific UI-related actions if (action.type === CE9178">'TOGGLE_SIDEBAR_PANEL' || action.type === CE9178">'SET_VIEW_MODE') { const state = store.getState(); // We only persist a slice of the state, not the entire store persistState(state.ui); } return result; };
Once the middleware is defined, register it when creating your store. If you are using the WordPress Data module, ensure you are providing this middleware during the registerStore initialization phase.
JAVASCRIPTimport { registerStore } from CE9178">'@wordpress/data'; import { persistenceMiddleware } from CE9178">'./middleware'; const storeConfig = { reducer, actions, selectors, // Note: WordPress Data stores support middleware via store enhancers // or by wrapping dispatch if using a custom Redux instance. }; registerStore(CE9178">'kb-plugin/store', storeConfig);
Now that you can write to localStorage, you need to read from it during initialization.
loadInitialState helper function.initialState definition, attempt to parse window.localStorage.getItem(STORAGE_KEY).try/catch block to handle corrupted JSON or disabled localStorage (a common scenario in private browsing modes).localStorage is a synchronous, blocking operation. Failing to use throttle or debounce will lead to dropped frames in the Gutenberg editor during rapid interactions.localStorage in "Incognito" mode. Always wrap these calls in a try/catch block to avoid crashing the editor UI.localStorage might cause errors. Always implement a version check or a "migration" function for your persisted state.We've moved beyond simple state management by implementing a persistence layer that bridges the gap between the volatile browser environment and the user's session. By leveraging Redux middleware, we've created a non-blocking, throttled system that keeps our Knowledge Base plugin's UI state consistent across reloads.
Up next: We will dive into creating Custom Hooks for React to abstract this state logic away from our components, further cleaning up our component architecture.
Master React performance by controlling re-renders. Learn to use React.memo, useMemo, and useCallback to keep your WordPress plugin interfaces fast and scalable.
Read moreMaster WordPress Data management. Learn to create custom stores, implement selectors and actions, and orchestrate global state across your blocks.
Advanced State Persistence