Keep a Local Toggle
Show and hide component details with a small TypeScript function.
Use local state for UI choices such as an expanded details section. Each copy of the component gets its own value. Real gameplay values belong in the Store.
Create an Empty component in Studio, replace its source, and save:
<template>
<div>
<button @click="toggle">Toggle details</button>
<p ui:show="expanded">Additional information</p>
</div>
</template>
<script lang="ts">
import { defineComponent, state } from "@calmui/runtime";
export default defineComponent<Record<string, unknown>, unknown>(() => {
const expanded = state(false);
function toggle(): void {
expanded.value = !expanded.value;
}
return { expanded, toggle };
});
</script>Double-click the component to preview it. Clicking the button should show and hide the paragraph. Put two copies in a View: clicking one should not toggle the other.
state(false) creates the value. The function changes .value, and the returned
names make both the value and function available to the template. ui:show
hides content while keeping its component state.
Separate Views also keep separate script state. In Unreal, an inventory View and a notifications View use isolated script contexts for the same Local Player. Both receive that player's Store updates and UI clock ticks. Share gameplay data through the Store, not through script globals. Keeping a View alive retains its context; destroying it releases its component state and timers.
Use computed for a value calculated from other values and watch when a change
needs a side effect. A watch returns a stop function; call it when you no longer
need to observe changes, or from onUnmount when the component is removed.
Anything the template shows must be state, computed, or props. The View
re-renders a component when a reactive value its template read changes, and
only then: a handler that only arms a timer or dispatches an action does not
re-render anything. A plain variable changed in place (a module-level object, an
array pushed into without assigning .value) is not observed, so the template
keeps showing the old value until something reactive changes.
Props also participate in these calculations. Read props.label inside a
computed callback to update a caption when its parent changes the label.
Props, including nested objects, are read-only; use state for local edits and
emit an event when the owner should accept a new value. See
Pass Values to Components.
Events without a click
Component events emitted from timers or prop watchers reach parent listeners
at the next view update, without requiring a click or pointer movement. A parent
can update local state in that listener; the view settles those changes before
rendering. Cyclic event/watch feedback is rejected after 1,024 emissions in one
update. A timer, action, emission, or diagnostic created inside a Store-driven
watcher remains owned by that component instance. Keep timer cleanup in
onUnmount so removed components cannot finish old work later.