Mesa guide / Reactivity
Shared state
Mesa has no store API. Shared state is an object exported from a plain JavaScript
module, and a component that imports it says which parts it follows with a $: line.
// store.js
export const user = { name: 'Ada' }
<script>
import { user } from './store.js'
$: user.name
</script>
<input bind:value={user.name} />
<p>Hello, {user.name}</p>
$: user.name has no body. It tells Mesa that this component re-renders when
user.name changes. Every component that watches the same path updates together.
Watch what you read
An imported binding is invisible to the compiler until you watch it.
$: user // the whole object, any change
$: user.name // one path
$: (cart.items, cart.total) // several paths in one line
A watched path also makes a const that reads it derived, so
const shout = user.name.toUpperCase() follows user.name once $: user.name is
there. Without the watch it computes once.
Share fields, not primitives
An imported number or string is a constant, even if the module reassigns its
export let. State that moves lives in a field on an exported object: store.count,
not count.
Writing from the module
Writes made inside a component are picked up automatically. A module that changes
its own state needs the same handle the components use, which watchProxy returns.
// store.js
import { watchProxy } from '@frontierjs/mesa/runtime'
export const cart = { items: [], total: 0 }
const _cart = watchProxy(cart)
export function add(item) {
_cart.items = [..._cart.items, item]
_cart.total = _cart.items.length
}
A write straight to cart.items from the module reaches nobody. Keep the reacting
in components and compute shared values where you write them, not where you read them.
For giving a lifetime to work that lives outside a component, see Lifetimes.
Spec: VISION.md § 5 · RULE 8