Reactivity in CellUI
At the heart of CellUI is the Signal. Unlike React's useState, which triggers a complete re-render of your component function, CellUI components execute exactly once. A signal is a reactive container that strictly updates only the DOM nodes that care about it.
Basic Signals
You create a signal by calling signal(initialValue).
import { signal, view } from '@cmj/cellui';
function Counter() {
// 1. Create the signal
const count = signal(0);
// 2. Mutate it via the .value property
const increment = () => {
count.value++;
};
// 3. Bind it directly into the view
return view`
<button onclick="${increment}">
Clicked ${count} times
</button>
`;
}Because count is a reference to the Signal class instance, CellUI binds it natively to the TextNode. When count.value++ happens, the button's text updates instantly in O(1) time without rebuilding the button.
Deep Object Signals (Proxies)
The true power of CellUI is its out-of-the-box support for Deep Signals via ES6 Proxies.
If you pass a JSON Object into a signal, CellUI recursively wraps it. You can mutate deep properties, and CellUI will efficiently update only the DOM nodes listening to that specific nested property!
const user = signal({
profile: {
name: 'Alice',
preferences: { theme: 'dark' }
}
});
function ProfileView() {
const toggleTheme = () => {
// This granular mutation works instantly!
user.value.profile.preferences.theme.value = 'light';
};
return view`
<!-- Binds only to the specific nested property -->
<div>Theme: ${user.value.profile.preferences.theme}</div>
<button onclick="${toggleTheme}">Toggle</button>
`;
}Side Effects (effect)
If you need to run arbitrary JavaScript code whenever a signal changes, use effect().
You do not need to declare a dependency array! CellUI tracks dependencies automatically based on which signals you read inside the effect block.
import { signal, effect } from '@cmj/cellui';
const searchQuery = signal("CellUI framework");
// This will log immediately, AND whenever searchQuery changes
effect(() => {
console.log("Searching for:", searchQuery.value);
});Because CellUI utilizes WeakRef internally for DOM bindings, signals do not cause detached DOM memory leaks when elements are removed from the page.