storage()

storage() wraps a default value and makes the variable persistent. It reads from localStorage when the component mounts, falls back to your default, and saves again on every assignment.

Nothing else changes: it is still an ordinary reactive let.

<script>
let theme = storage('light')
</script>

<button onclick="theme = theme === 'light' ? 'dark' : 'light'">
  Theme is {theme} - click to switch
</button>
output

Click it, reload the page, and the theme is still the one you chose.

Any Type

Strings, numbers, booleans, objects and arrays are all serialised for you:

source
<script>
let theme = storage('light')                    // String
let fontSize = storage(16)                      // Number
let soundEnabled = storage(true)                // Boolean
let user = storage(null)                        // Null (until set)
let prefs = storage({ dark: false, size: 14 }) // Object
let recentItems = storage([])                   // Array
</script>

Keys and sessionStorage

The storage key is the variable's name with a jaf: prefix, so let theme = storage('light') writes jaf:theme.

Pass a string first to choose your own key, and an options object last to use sessionStorage, which lasts until the tab closes:

source
let theme = storage('light')                             // jaf:theme
let theme = storage('ui:theme', 'light')                 // jaf:ui:theme
let draft = storage('', { storage: 'session' })          // sessionStorage
let draft = storage('form:draft', '', { storage: 'session' })

An object on its own is a default value, not options - storage({ dark: false }) means what it looks like. Options are only read from a final argument, and anything JAF cannot make sense of is reported in the console by variable name rather than dropped in silence.

A Worked Example

A form draft that survives a reload is three characters of difference from one that does not:

<script>
let draft = storage({ title: '', body: '' })

function clearDraft() {
  draft = { title: '', body: '' }
}
</script>

<input bind:value={draft.title} placeholder="Title" />
<textarea bind:value={draft.body} placeholder="Type here, then reload the page"></textarea>

<button onclick="clearDraft()">Clear</button>
output

To clear a stored value, assign the default back to it - that is saved like any other assignment.

To wipe everything, use localStorage.clear() and reload.

Outside a Component

The same persistence is available as a plain API for code that is not a component:

source
import { persistedStore, persisted } from 'jafjs'

// A reactive object, persisted under the key you give it
const settings = persistedStore('app-settings', { theme: 'light', language: 'en' })
settings.theme = 'dark'   // saved

// A single value
const counter = persisted('counter', 0)
counter.value++           // saved

// Options, and manual control
persistedStore('session', initialState, { storage: 'session', debounce: 100 })
settings.$persist()       // force a save
settings.$clear()         // drop the stored copy
  • url() - state that lives in the query string instead
  • unite() - share one stored value across files