Storing Data Beyond a Single User Session: A Progressive Web App Solution
The Limitations of localStorage
When building a progressive web app (PWA), you may want to store information that persists beyond a single user session. This data should be accessible even when the user is offline, allowing them to continue using the app meaningfully. One might think of using Window.localStorage, a longstanding API that stores data beyond a single session. However, it presents a few key problems:
- It’s synchronous, which can lead to performance issues.
- It can’t be used in the context of a Worker or a ServiceWorker.
- It only stores strings, which can be an inconvenience.
IndexedDB: A Powerful Alternative
Fortunately, there’s an alternative offline storage mechanism available in browsers called IndexedDB. It’s a transactional database system that lets you store and retrieve objects indexed with a key. Although it’s powerful, its API can be complex and overwhelming.
IDB-Keyval: A Simple Abstraction
That’s where IDB-Keyval comes in – a super-simple-small promise-based keyval store implemented with IndexedDB. Its API is essentially equivalent to localStorage, but with a few lovely differences:
- It’s promise-based, allowing for non-blocking operations.
- It can store anything structured-clonable, such as numbers, arrays, objects, dates, blobs, and more.
Using IDB-Keyval in a React App
Let’s demonstrate how to use IDB-Keyval in a TypeScript React app. We’ll create a simple app that enables users to choose between a dark mode and the regular display. We’ll then persist this preference using IDB-Keyval, allowing it to work both online and offline.
import { createStore } from 'idb-keyval';
const store = createStore('my-store');
function App() {
const [theme, setTheme] = useState('light');
useEffect(() => {
store.set('theme', theme);
}, [theme]);
return (
);
}
Implementing IDB-Keyval as a React Hook
To take it a step further, let’s create a reusable React hook called usePersistentState. This hook is modeled after the API of useState and allows us to persist state beyond page refreshes.
import { createStore } from 'idb-keyval';
const store = createStore('my-store');
function usePersistentState(key, initialState) {
const [state, setState] = useState(initialState);
useEffect(() => {
store.set(key, state);
}, [key, state]);
useEffect(() => {
store.get(key).then((value) => setState(value));
}, [key]);
return [state, setState];
}
The Benefits of Offline Storage
Offline storage leads to better user experiences. By using IDB-Keyval, we can build PWAs that provide users with a seamless experience, even when they’re offline. Whether you’re building a React, Vue, or Angular app, this solution can help you achieve offline storage with ease.
Learn more about building PWAs with offline storage.