All Articles

Persistent State in Vue/Svelte NativeScript apps

What is NativeScript?

NativeScript is a framework for building mobile apps with JavaScript. At the time of writing, there’s official support for Angular, Vue and plain JavaScript/TypeScript.

There’s also a community project to allow you to build native apps with Svelte v3. Svelte has a beautiful and detailed tutorial that is run entirely in the browser. Be careful if you click this link: once you start the tutorial you’ll want to spend the time to get to the end.

What do I mean by persistence?

Let’s assume we have a ‘to do’ app. When a new item is added, we would like:

  • The new item to be shown on the screen, in the list of todos
  • The new item to be stored somewhere, so it can be used by other parts of the app (e.g. maybe we have a ‘summary’ screen which shows stats about how many todos we have)
  • Be saved on the device, so that when the app is quit and re-opened, all our todos are still intact

How do we persist things now?

In components

If you’re using Vue, then your state is maintained in the component tree. You know it’s there, because otherwise the data shown on your screen would never change. Many people use Vue to add a little interactivity to specific pages/forms in a traditional web app. If that’s how you use Vue, then you probably persist your data by POSTing the results to a form or something, and you don’t need to worry about maintaining state in some clean way.

Using a global state store

If you’re developing a single-page app (SPA) or more complicated Vue application, then you’re probably using Vuex to maintain a single state across all your components. (For those new to Vue: Vuex does a similar job to Redux or MobX).

So how do we keep our state even when the app quits?

When you’re developing for a browser, you use the LocalStorage key-value store. That’s fine as it goes, but you probably don’t want to have calls to LocalStorage.setItem and LocalStorage.getItem all over your code.

If the application state (stored in e.g. Vuex) isn’t too large, then you might want to persist the whole thing in LocalStorage. That’s where a couple of handy packages come in:

Both of these packages will automatically sync your Vuex store with the browser’s LocalStorage

Can we use the same approach in native apps?

Almost. Native apps developed with NativeScript don’t have LocalStorage. Thankfully, there’s a package that fixes that: nativescript-localstorage. After importing this package, you can do LocalStorage.setItem etc. Under the hood, it uses file system access to create and maintain a file called localStorage.db which contains a JSON string of your app’s state.

What about Svelte?

There’s a nice example of how to do this with the previous version of svelte. The code below is from https://github.com/sveltejs/template-store:

export default function useLocalStorage(store, key) {
	const json = localStorage.getItem(key);
	if (json) {
		store.set(JSON.parse(json));
	}

	store.on('state', ({ current }) => {
		localStorage.setItem(key, JSON.stringify(current));
	});
}

This code does two things:

  1. When it’s first imported, it checks if the old state was stored in LocalStorage. If so, it parses it adds it into the store.
  2. Whenever the state changes (store.on), it writes the entire state to a JSON string, and writes it to local storage again.

To make it work, this file needs to run once after the store is created. From main.js in the same repo as above:

import { Store } from 'svelte/store.js';
import useLocalStorage from './useLocalStorage.js';

const store = new Store({
	name: 'world'
});
useLocalStorage(store, 'my-app');

All that is needed to make the above work in a NativeScript app is to add import localStorage from 'nativescript-localstorage'; before using localStorage.

The API for Svelte has changed a lot in the run-up to v3, and on doesn’t appear in the documentation. However, you can use store.subscribe instead of store.on.

Here’s a repo with a simple Svelte Native app with persistent state.