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: ''
});