-
Notifications
You must be signed in to change notification settings - Fork 6
Using state in templates
When you insert reactive entities (ReactiveValue
s, ReactiveArray
s) into a template, the template will automatically synchronize with the state. Additionally, when assigning state to value
, prop:value
, prop:valueAsNumber
, or prop:valueAsDate
, the state will be updated when user input comes in.
Here's an example:
const username = reactive("");
const initials = computed(() =>
username.value
.trim()
.split(/\s/)
.filter(Boolean)
.map(([initial]) => initial + ". ")
.join("")
);
const template = html`
<input type="text" placeholder="Type your name…" prop:value=${username} />
Initials: ${initials}
`;
In this example, the user can enter their name in the text field, and the initials next to the field will be automatically updated as the user types. Note how the transformation from the source state (username
) to derived state (initials
) is wrapped in computed()
. Whenever you want to compute new reactive values from existing ones, you need to wrap them in computed()
— otherwise the library won't have any way of knowing how to track changes. See documentation on computed()
for more details.
By default, the library has two-way data binding. However, you can opt out of this behavior. reactive.readonly
gives you a readonly version of the reactive entity, and the recipient won't be able to update it. You can also unbox the reactive value using reactive.value
, and with it, there will be no data binding at all, because the recipient won't know it was ever reactive.
const state = reactive(0);
const template = html`
<!-- two-way data binding -->
<input type="number" prop:valueAsNumber=${state} />
<!-- one-way data binding -->
<input type="number" prop:valueAsNumber=${state.readonly} />
<!-- no data binding, pass as value -->
<input type="number" prop:valueAsNumber=${state.value} />
<!-- no data binding, pass as reactive -->
<custom-number-input prop:valueAsNumber=${value.pass} />
<!-- no data binding, pass as readonly reactive -->
<custom-number-input prop:valueAsNumber=${value.readonly.pass} />
`;
When you assign a reactive value to a property or attribute, it will be bound to it, and it will receive its contained value. In other words, the first example above will set the valueAsNumber
property on the input element to the current numeric value held by the state
ReactiveValue. To pass the ReactiveValue to an element as-is, without any binding, you can use the pass
property on ReadonlyReactiveValue
. This can be useful if the component expects a reactive value as a property.
As mentioned in the Templating article, partially applied attribute values are not allowed, and you will instead need to compute a new reactive string if you wish to concatenate several reactive strings and/or regular strings.
const favoriteColor = reactive("#ffffff");
const template = html`
<div style=${computed`background-color: ${favoriteColor}`}>
What's your favorite color? <br />
<input type="color" prop:value=${favoriteColor} />
</div>
`;
In addition to inserting singular values into templates, you may also insert an Array
or a ReactiveArray
. Each item in the array will be inserted into the template. Naturally, in the case of ReactiveArray
s, the DOM will be kept up to date with changes to the array.
Here's an example of a minimal TODO list app utilizing reactive arrays:
const tasks = reactive([
{
done: true,
name: "Pet the cat",
},
{
done: false,
name: "Travel the world",
},
{
done: false,
name: "Catch all Pokémon",
},
]);
const template = html`
<h1>TODO</h1>
<ul>
${tasks.map((task, i) => html`
<li style=${computed(() => `color: ${task.done.value ? "green" : "red"};`)}>
<label>
<input type="checkbox" prop:checked=${task.done} />
${task.name}
</label>
<button on:click=${() => tasks.splice(i.value, 1)}>🚮</button>
</li>
`)}
</ul>
<form on:submit=${event => {
event.preventDefault();
tasks.push({
done: false,
name: event.target.newTask.value,
});
}}>
<input type="text" name="newTask" />
<button>Add</button>
</form>
`;
- Reactivity
-
Templating
- Props vs. attributes (
prop:
) - Adding event listeners (
on:
) - Getting a reference to an element (
Ref
) - Using state in templates
- Animating elements (
destiny:mount
,destiny:unmount
) [to be written]
- Props vs. attributes (
-
Components
- Usage in templates
- Managing state [to be written]
- Styling components
- Passing props [to be written]
register()