polemius/recoil-persist

can we use indexedb?

koraysels opened this issue · 3 comments

Can we use indexDB instead of localStorage? There is an issue in latest electron wrapper that clears localStorage when the app closes...

Here is a example how you could use indexDB:

import React from "react";
import ReactDOM from "react-dom/client";
import { atom, RecoilRoot, useRecoilState } from "recoil";
import { recoilPersist } from "recoil-persist";

const getIndexDBStorage = async () => {
  const openConnection = async () => {
    return new Promise((resolve, reject) => {
      const DBOpenRequest = window.indexedDB.open("recoil-persist");

      DBOpenRequest.onerror = () => reject("Error open database");
      DBOpenRequest.onsuccess = (event) => {
        resolve(event.target.result);
      };

      DBOpenRequest.onupgradeneeded = (event) => {
        const db = event.target.result;
        db.createObjectStore("recoil-persist");
      };
    });
  };

  const database = await openConnection();

  const storage = {
    setItem: (key, value) => {
      if (database === undefined) {
        return;
      }

      return new Promise((resolve, reject) => {
        const putRequest = database
          .transaction(["recoil-persist"], "readwrite")
          .objectStore("recoil-persist")
          .put(value, key);

        putRequest.onsuccess = () => {
          resolve();
        };

        putRequest.onerror = () => {
          reject();
        };
      });
    },
    getItem: (key) => {
      if (database === undefined) {
        return;
      }
      return new Promise((resolve, reject) => {
        const result = database
          .transaction(["recoil-persist"], "readwrite")
          .objectStore("recoil-persist")
          .get(key);

        result.onsuccess = (event) => {
          resolve(event.target.result);
        };
        result.onerror = () => {
          reject();
        };
      });
    },
  };

  return storage;
};

const { persistAtom } = recoilPersist({
  storage: await getIndexDBStorage(),
});

const counterState = atom({
  key: "count",
  default: 0,
  effects_UNSTABLE: [persistAtom],
});

function App() {
  const [count, setCount] = useRecoilState(counterState);
  return (
    <div>
      <h3>Counter: {count}</h3>
      <button onClick={() => setCount(count + 1)}>Increase</button>
      <button onClick={() => setCount(count - 1)}>Decrease</button>
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <RecoilRoot>
      <App />
    </RecoilRoot>
  </React.StrictMode>
);

nice! going to give it a go ;)

this works! thank you so much, Converted it to typescript:

const getIndexDBStorage = async () => {
    const openConnection = async () => {
        return new Promise<IDBDatabase>((resolve, reject) => {
            const DBOpenRequest = window.indexedDB.open("recoil-persist");

            DBOpenRequest.onerror = () => reject("Error open database");
            DBOpenRequest.onsuccess = () => {
                resolve(DBOpenRequest.result as IDBDatabase);
            };

            DBOpenRequest.onupgradeneeded = () => {
                const db = DBOpenRequest.result as IDBDatabase;
                db.createObjectStore("recoil-persist");
            };
        });
    };

    const database = await openConnection();

    const storage = {
        setItem: (key: string, value: any) => {
            if (database === undefined) {
                return;
            }

            return new Promise<void>((resolve, reject) => {
                const putRequest = database
                    .transaction(["recoil-persist"], "readwrite")
                    .objectStore("recoil-persist")
                    .put(value, key);

                putRequest.onsuccess = () => {
                    resolve();
                };

                putRequest.onerror = () => {
                    reject();
                };
            });
        },
        getItem: (key: string): string | Promise<string> | null => {
            if (database === undefined) {
                return null;
            }
            return new Promise<string>((resolve, reject) => {
                const result = database
                    .transaction(["recoil-persist"], "readwrite")
                    .objectStore("recoil-persist")
                    .get(key);

                result.onsuccess = () => {
                    resolve(result.result);
                };
                result.onerror = () => {
                    reject();
                };
            });
        },
    };

    return storage;
};

export default getIndexDBStorage;