redux-persit with NeDB

I built a small package for integrating NeDB with redux-persist. You can check it out on GitHub

The problem

We want to persist our store after the user has closed the application. We are using redux for state management, and it doesn’t matter much if we’re on React or Vue or wherever you are using your redux.

Tools of the Trade

We will be using redux-persist as our solution for persisting the redux store. We will use NeDB as our long-term store. We will have to create a storage adapter to connect redux-persist and NeDB.

Preparations

We have a few things we need to install first

    yarn add nedb redux-persit deep-parse-json

Persisting redux store

Okay now start by creating our redux store using Redux Toolkit

import { combineReducers, configureStore } from "@reduxjs/toolkit";
import someOtherReducer from "./reducers/someOther";

const reducer = (state = [], action) => {
  return state;
};

const rootReducer = combineReducers({
  reducer,
  someOtherReducer,
});

const store = configureStore({
  reducer: rootReducer,
});

export default store;

Now that we have our store configured, let’s bring in redux-persist with the default configuration

// ...rest of the imports
import { persistReducer } from "redux-persist";
import storage from "redux-persist/lib/storage"; // defaults to localStorage for web

// ...rest of the code
const persistConfig = {
  key: "root",
  storage,
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

Let’s update our store to use the new persistedReducer

// ...rest of the imports
import { persistStore } from 'redux-persist'

const store = configureStore({
  reducer: persistedReducer,
});

export default store

export {
    persistor: persistStore(store)
}

Assuming you have already set up your redux provider and followed the quickstart guide with redux-persist, we should be on the same page now. If not, there is a link to the quick guide at the bottom of this page.

Now let’s get on the interesting part.

Custom Storage Engine

// createNeDBStorage.js
import path from "path"
import { deepParseJson } from "deep-parse-json"
import Datastore from "nedb

const createNeDBStorage = async (config) => {
	const store = new Nedb({
		filename: config.databasePathname || "database.db",
		autoload: true,
        inMemoryOnly: !!config.inMemoryOnly
	});

	return {
		getItem: (key) => {
			return new Promise((resolve, reject) => {
				store.findOne({ key }, (err, data) => {
					if (err) resolve(JSON.stringify({}));
					if (!data) resolve(JSON.stringify({}));
					resolve(JSON.stringify(data));
				});
			});
		},
		setItem: (key, item) => {
			return new Promise((resolve) => {
				resolve(
					store.update(
						{ key },
						{ $set: { ...deepParseJson(item) } },
						{ upsert: true, new: true },
					),
				);
			});
		},
		removeItem: (key) => {
			return new Promise((resolve) => {
				resolve(store.remove({ key }));
			});
		},
	};
};

export default createNeDBStorage

We are using deepParseJson just in case your state has deep objects, which it most probably will.

Now lets update redux-persist to use our new storage engine.

//store.js
import createNeDBStorage from "./createNeDBStorage";
import { deepParseJson } from "deep-parse-json";

const persistConfig = {
  key: "root",
  storage: createNeDBStorage(),
  // we pass a custom deserializer that does deep parse
  deserialize: deepParseJson,
};

//...rest of the code

You should be good to go now