TinyBase logoTinyBase

Todo App v3 (persistence)

In this demo, we build a yet more complex 'Todo' app, complete with persistence and a schema.

In the Todo App v1 (the basics) demo and the Todo App v2 (indexes) demo, refreshing the page reset all the todos, which didn't make it very useful. In this version, we demonstrate the basics of how to persist data from a Store.

When data is persisted, it also valuable to have a schema for it, so in this demo we also add a simple schema for the todos.

We're making changes to the Todo App v2 (indexes) demo.

Additional Initialization

We will call the createLocalPersister function to create a Persister object that persists the the main Store object in the browser's local store. Similarly, the createSessionPersister function will create a Persister object that persists the Store object containing the user's current view:

 <script src="/umd/tinybase.js"></script>
+<script src="/umd/persister-browser.js"></script>
 <script src="/umd/ui-react.js"></script>
 const {createIndexes, createStore} = TinyBase;
+const {createLocalPersister, createSessionPersister} = TinyBasePersisterBrowser;
 const {
   CellView,
   Provider,
   SliceView,
   useAddRowCallback,
   useCell,
   useCreateIndexes,
+  useCreatePersister,
   useCreateStore,
   useSetCellCallback,
   useSetValueCallback,
   useValue,
 } = TinyBaseUiReact;

Adding a TablesSchema

A Store has a setTablesSchema method which can be used to describe a schema of each Cell present in each Table. Here we will indicate that the text Cell and type Cell are strings, and we default the done field to false. The type can only be one of the values of the TYPES array:

 const TYPES = ['Home', 'Work', 'Archived'];
+const SCHEMA = {
+  todos: {
+    text: {type: 'string'},
+    done: {type: 'boolean', default: false},
+    type: {type: 'string', default: 'Home', allow: TYPES},
+  },
+};

Persisting the Store

We create and memoize a Persister object for the main Store object. We'll start it auto-loading from the browser's local storage immediately, but we can also provide INITIAL_TODOS as a default if nothing has been previously saved. We also set the Persister object to auto-save, creating a continuous synchronization between the in-memory version of the Store object and the copy of it in the browser's local storage.

Note that we don't set the initial data of the Store object when we first create it, since it might have been persisted into the browser's local storage from a previous session, and we want to pick it up with the first load. We do configure the schema on creation though:

-  const store = useCreateStore(() => createStore().setTables(INITIAL_TODOS));
+  const store = useCreateStore(() => createStore().setTablesSchema(SCHEMA));
+  useCreatePersister(
+    store,
+    (store) => createLocalPersister(store, 'todos/store'),
+    [],
+    async (persister) => {
+      await persister.startAutoLoad(INITIAL_TODOS);
+      await persister.startAutoSave();
+    },
+  );

We do something similar for the viewStore, so that reloads preserve the type currently being viewed. Instead of local storage, we'll use the browser's session storage. This means that if the user has two browser windows open, the UI changes to one won't mysteriously affect the other:

-  const viewStore = useCreateStore(() =>
-    createStore().setValue('type', 'Home'),
-  );
+  const viewStore = useCreateStore(() =>
+    createStore().setValuesSchema({type: {type: 'string', default: 'Home'}}),
+  );
+  useCreatePersister(
+    viewStore,
+    (store) => createSessionPersister(store, 'todos/viewStore'),
+    [],
+    async (persister) => {
+      await persister.startAutoLoad();
+      await persister.startAutoSave();
+    },
+  );

Make some changes to the todos and then reload your browser!

We now have a fairly useful app for tracking todos and persisting the state. Please continue to the Todo App v4 (metrics) demo.