# Reactivity Issues ## Data Not Updating **Issue:** UI doesn't update when data changes **Check 1:** Missing `$` prefix for bidirectional binding? ```typescript // Not bidirectional - won't update automatically // Bidirectional - updates automatically ``` **Check 2:** Using handler when bidirectional binding would work? ```typescript // Unnecessary handler const toggle = handler(({ detail }, { item }) => { item.set.key("done").set(detail.checked); }); // Use bidirectional binding instead ``` **Check 3:** Wrong event name for handler? Each component has specific event names. Check @common/components/COMPONENTS.md for the right event: ```typescript // Wrong event name // Correct event name ``` ## Filtered/Sorted List Not Updating **Issue:** Filter or sort doesn't update when dependencies change **Problem:** Inline filtering/transformations in JSX don't create reactive dependencies ```typescript {items.filter(item => !item.done).map(...)} {/* Won't update! */} ``` **Solution:** Use `computed()` outside JSX, then map over the result ```typescript const activeItems = computed(() => items.filter(item => !item.done)); {activeItems.map(...)} {/* Updates reactively! */} ``` **The Pattern:** Compute transformations (filter, sort, group) outside JSX using `computed()`, then map over the computed result inside JSX. Mapping over `computed()` results is the canonical pattern. ## Conditional Rendering Not Working **Issue:** Ternary operator doesn't work for conditional rendering **Problem:** Ternaries don't work for conditional elements ```typescript {showDetails ?
Details
: null} {/* Won't work! */} ``` **Solution:** Use `ifElse()` for conditional rendering ```typescript {ifElse(showDetails,
Details
, null)} {/* Works! */} ``` **Note:** Ternaries DO work in JSX attributes for simple values: ```typescript // Ternaries work in attributes {item.title} ``` ## Variable Scoping in Reactive Contexts **Issue:** Can't access variable from outer scope in `computed()` **Problem:** Variables from outer scopes aren't accessible in nested reactive contexts ```typescript {categories.map((category) => (
{computed(() => items.filter(i => i.category === category) // category not accessible! )}
))} ``` **Solution:** Pre-compute grouped data ```typescript const groupedItems = computed(() => { const groups: Record = {}; for (const item of items) { if (!groups[item.category]) groups[item.category] = []; groups[item.category].push(item); } return groups; }); {categories.map((category) => (
{(groupedItems[category] ?? []).map(item => (
{item.title}
))}
))} ``` **Related issue with lift():** The same scoping limitation applies to `lift()`. See @common/concepts/reactivity.md for the workaround pattern and explanation of frame-based execution. ## See Also - @common/concepts/reactivity.md - Reactivity system fundamentals - @common/components/COMPONENTS.md - Component binding patterns - @common/components/CELL_CONTEXT.md - Debugging cell values