npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

redux-flexible-backup

v0.4.0

Published

Flexible Redux state backup/restore and undo/redo systems

Readme

Redux Flexible Backup

A fully-typed configurable backup/restore system for your Redux state.

Useful for:

  • Saving and restoring state from localStorage (included!)
  • Continually backing up your state to sessionStorage (included!)
  • Creating a robust, memory-efficient undo/redo system (included!)
  • Sending/recieving your state from a server or external database

What do you mean 'configurable'?

Sometimes, your Redux state contains data that you'd rather not save or transmit. That might include data which could be computed/recreated from the rest of the state, application data that doesn't need to be undone/redone, and more.

When creating or loading backups using this package, you always specify a "backup interface". This contains per-slice configuration that decides what gets saved and what doesn't. You'll get to specify a save/load pair of functions for each slice in your state: meaning you could even compress the data if you'd like.

All this is fully-typed, meaning that if you're using Typescript, the results of any backups will be automatically computed from the save function's return values.

Usage Example

// Given a state
const state = { 
  // With one slice
  slice: {
    // With some data we'd want to save
    dataToSave: 'my data',

    // And some we wouldn't
    dataWeDontNeedToSave: 55
  }
};

// We can define a backup interface for this state
const backupInterface = {
  // That tells it how to store each slice
  slice: { 
    // That converts the slice to what we actually need to save
    save: (slice) => slice.dataToSave,

    // And tells the system how to restore from that save
    load: (stored) => ({dataToSave: stored, dataWeDontNeedToSave: 0})
  }
};

// And use that to create backups
const backup = createBackup(state, backupInterface);

// Which we can later restore
const restored = loadBackup({}, backupInterface, backup);

// Want an easy to use undo/redo system? Just wrap your reducer
const undoableReducer = createUndoableReducer(myReducer, backupInterface);

// Anytime you run an action with '/undoable/' in the type, a backup point is automatically saved
const newState = undoableReducer(state, { type: 'my/undoable/action' });

// Which you can undo/redo
const undoneState = undoableReducer(newState, UndoActions.undo);
const redoneState = undoableReducer(newState, UndoActions.redo);

// You can also iterate the history to see what's happened
for(const moment of iterateUndoHistory(newState)) {
  // .. do something with moment ..
}

Backup Interfaces

The backup/restore feature is configured by backup interfaces. These are responsible for simplifying your state into the minimal object required to save and restore. This is especially useful if your state contains a lot of data that can be re-created from some minimal set or doesn't need to be stored.

There are two types of backup interfaces: slice and state.

A slice backup interface is an object with two methods: save and load.

The save method should take a slice object and return what must be stored. The return value really can be anything.

The load method takes whatever type you returned in save and must recreate the slice.

// A simple slice backup interface
const sliceBackupInterface = {
  save: (slice) => slice.dataToSave,
  load: (stored) => ({dataToSave: stored, dataWeDontNeedToSave: 0})
}

A state backup interface is just an object mapping slices to slice backup interfaces.

// State backup interface
const stateBackupInterface = {
  // Use sliceBackupInterface to backup/restore the `mySlice` slice
  mySlice: sliceBackupInterface
}

The fields of your state backup interface should match the field names of your state object.

Any slices in the state that don't match up with some slice backup interface in the state backup interface are ignored in save/load.

If you want your slice to just be copied in its entirety into the backup, use the premade CopySliceBackupInterface.

NEW: State Backup Interfaces can now also contain State Backup Interfaces as children, allowing you to recursively define state.

Redux Toolkit Plugin

If you're using Typescript and want to reduce the typing hassle of using this plugin, you can use createBackupSlice, a wrapper for the Redux Toolkit createSlice. It adds an extra helper function to the resulting slice object to quickly create backup interfaces for your slice.

// Use just like createSlice
const mySlice = createBackupSlice({
  name: 'mySlice',
  initialState: {},
  reducers: {}
});

// Type deduction is automatic. "state" will automatically be typed to the state type of your slice and stored will automatically be typed to the return value of the first function
export const mySliceBackupInterface = slice.createBackupInterface( state => ..., stored => ...);

// The type of mySliceBackupInterface is automatically deduced, so if we use it to create a state backup
const stateBackupInterface = { mySlice: mySliceBackupInterface };

// And call createBackup
const backup = createBackup(currentReduxState, stateBackupInterface);

// all of backup's fields will be automatically typed properly given the return value of the save function above in createBackupInterface

It can also automatically create properly named undoable actions (see Undo/Redo below) by adding reducers to the undoableReducers option.

const mySliceWithSomeUndoableActions = createBackupSlice({
  name: 'mySlice',
  initialState: {},
  reducers: {
    basicAction: ....
  },
  undoableReducers: {
    undoableAction: ...
  }
});

This function plays nicely with Typescript, meaning mySliceWithSomeUndoableActions.actions will contain both basicAction and undoableAction.

Undo/Redo

To use undo/redo, just wrap your reducer with createUndoableReducer (see the Usage Example above).

The resulting state will have three extra fields: history, present, and future.

present stores a backup of the state as it was the last time any undoable action was run.

history contains the past states. They are stored as diffs so you won't be able to access them directly.

future are redoable states created when you use UndoActions.undo. This is what will be restored, in order, when UndoActions.redo is called.

To iterate the history, use iterateUndoHistory. This will automatically unpack diffs and can be used in a for ... of ... loop.

Storage

This package also includes a plugin for saving backups to local or session storage.


// Save to storage using an interface
saveToStorage(localStorage, "STORAGE_KEY", myReduxState, myStateBackupInterface);

// Load from storage
const loadedState = loadFromStorage<MyStateType>({}, localStorage, "STORAGE_KEY", myStateBackupInterface);

If you want to save a backup of your state to session storage after each action, you can use the included session storage middleware.


// Create an initial state by loading from the session
const initialState = loadInitialStateFromSession({}, myStateBackupInterface, "SESSION_KEY");

// Create middleware
const middleware = createSessionMiddleware<MyStateType>(myStateBackupInterface, "SESSION_KEY");

// Install it when creating your state
const extensions = compose(applyMiddleware(middleware));
const store = createStore(rootReducer, initialState, extensions);