Local State
There is no state API to learn.
let is reactive state; const is a plain value. Anything you assign
to a let updates the DOM that reads it.
<script>
let name = 'World'
let count = 0
</script>
<p>Hello, {name}! You have clicked {count} times.</p>
<button onclick="count++">Click me</button>
<button onclick="name = 'JAF'">Rename</button>
<style>
button {
margin-right: 0.4rem;
padding: 0.35rem 0.75rem;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--bg-secondary);
color: var(--text-primary);
cursor: pointer;
}
</style>Hello, World! You have clicked 0 times.
Functions are usually const: the function itself never changes, even though it
changes reactive variables when it runs.
Derived Values
A let whose initialiser reads other reactive variables is derived: JAF
recomputes it whenever any of them change.
Derived values can build on other derived values.
<script>
let price = 10
let quantity = 2
// Derived: recomputed whenever price or quantity changes.
let total = price * quantity
</script>
<p>{quantity} x {price} = {total}</p>
<button onclick="quantity++">One more</button>
<style>
button {
padding: 0.35rem 0.75rem;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--bg-secondary);
color: var(--text-primary);
cursor: pointer;
}
</style>2 x 10 = 20
Only expressions over reactive variables are derived. A literal, a
new Date() or a fetch() call reads no reactive state, so it is
ordinary state that keeps whatever you assign it.
Objects and Arrays
Mutating deeply works as well as replacing: user.age++ and
todos.push(...) both update the DOM.
<script>
let user = { name: 'Alice', age: 30 }
let todos = []
</script>
<p>{user.name} is {user.age}. Todos: {todos.length}</p>
<button onclick="user.age++">Birthday</button>
<button onclick="todos.push({ text: 'New todo' })">Add a todo</button>
<style>
button {
margin-right: 0.4rem;
padding: 0.35rem 0.75rem;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--bg-secondary);
color: var(--text-primary);
cursor: pointer;
}
</style>Alice is 30. Todos: 0
Side Effects
effect() runs its body once on mount and again whenever anything it read
changes.
Effects are torn down with the component, so there is nothing to unsubscribe.
<script>
let count = 0
effect(() => {
console.log('Count changed:', count)
// Runs on initial mount AND every update
})
</script>
Related
- Reactivity - how the tracking works
- storage() - the same state, persisted
- unite() - the same state, shared across files