State (Store)
State provides deep reactivity for objects and arrays. Unlike signals which only track reassignment, state tracks nested property changes automatically.
The Problem with Signals + Objects
// Signals only react to reassignment
const user = signal({ name: 'Alice', age: 25 });
user.value.age = 26; // ❌ Won't trigger updates!
user.value = { ...user.value, age: 26 }; // ✅ Works, but verbose
// Arrays have the same issue
const items = signal([1, 2, 3]);
items.value.push(4); // ❌ Won't trigger updates!
items.value = [...items.value, 4]; // ✅ Works, but tedious
State to the Rescue
const { state } = Lightview;
// Deep reactivity - mutations work!
const user = state({ name: 'Alice', age: 25 });
user.age = 26; // ✅ Triggers updates!
user.name = 'Bob'; // ✅ Triggers updates!
// Arrays just work
const items = state([1, 2, 3]);
items.push(4); // ✅ Triggers updates!
items[0] = 10; // ✅ Triggers updates!
items.sort(); // ✅ Triggers updates!
Nested Objects
State tracks changes at any depth:
const app = state({
user: {
profile: {
name: 'Alice',
settings: {
theme: 'dark',
notifications: true
}
}
},
items: []
});
// All of these trigger updates:
app.user.profile.name = 'Bob';
app.user.profile.settings.theme = 'light';
app.items.push({ id: 1, text: 'Hello' });
In the UI
const todos = state([
{ text: 'Learn Lightview', done: true },
{ text: 'Build app', done: false }
]);
div(
ul(() => todos.map((todo, i) =>
li(
input({
type: 'checkbox',
checked: todo.done,
onchange: () => todos[i].done = !todos[i].done
}),
span(todo.text)
)
)),
button({ onclick: () => todos.push({ text: 'New', done: false }) }, 'Add')
)
Array Methods
All mutating array methods are reactive:
const items = state([1, 2, 3]);
items.push(4); // Add to end
items.pop(); // Remove from end
items.shift(); // Remove from start
items.unshift(0); // Add to start
items.splice(1, 1); // Remove at index
items.sort(); // Sort in place
items.reverse(); // Reverse in place
items.fill(0); // Fill with value
Named State (lightview-x)
Like signals, state can be named for global access:
// Register named state
const appState = state({ count: 0, user: null }, 'app');
// Retrieve elsewhere
const sameState = state.get('app');
// Get or create with default
const settings = state.get('settings', { theme: 'light' });
Signal vs State
| Use Signal | Use State |
|---|---|
| Primitives (numbers, strings, bools) | Objects with nested properties |
| Simple objects (replace whole thing) | Objects you'll mutate in place |
| Arrays you'll replace | Arrays you'll push/pop/splice |
| Slightly better performance | More convenient API |
Pro Tip
You can mix both! Use signals for simple values and state for complex structures:
const isLoading = signal(false); // Simple boolean → signal
const error = signal(null); // Simple value → signal
const items = state([]); // Array to mutate → state
const formData = state({ // Object to mutate → state
name: '',
email: '',
message: ''
});