How Reactivity Works

WakaPAC's reactivity system automatically synchronizes your data with the DOM. Change a property, and the UI updates - no manual DOM manipulation required.

explanation

The Basics

When you create a WakaPAC component, all properties in your abstraction object become reactive:

wakaPAC('#app', {
    count: 0,

    increment() {
        this.count++;  // Change is detected, DOM updates scheduled
    }
});

WakaPAC's reactivity engine:

  • Creates proxies for all properties in your abstraction object
  • Tracks dependencies - which DOM elements reference which properties
  • Queues updates when properties change, avoiding redundant operations
  • Batches DOM changes in microtasks for optimal performance
  • Updates selectively - only affected DOM elements are modified

The Reactivity Pipeline

Deep Reactivity

Nested Objects

WakaPAC recursively wraps nested objects in proxies, making changes at any depth reactive:

<div id="app">
    <p>{{user.name}}</p>
    <p>Theme: {{user.preferences.theme}}</p>
    <button data-pac-bind="click: changeTheme">Toggle Theme</button>
</div>

<script>
    wakaPAC('#app', {
        user: {
            name: 'John',
            preferences: {
                theme: 'dark'
            }
        },

        changeTheme() {
            // Deep property changes trigger reactivity
            this.user.preferences.theme =
                this.user.preferences.theme === 'dark' ? 'light' : 'dark';
        }
    });
</script>

Array Mutations

WakaPAC intercepts array mutator methods (push, pop, splice, shift, unshift, sort, reverse) to trigger updates automatically:

<div id="app">
    <ul data-pac-bind="foreach: todos" data-pac-item="todo">
        <li>{{todo.text}} (Item {{$index}})</li>
    </ul>
    <button data-pac-bind="click: addTodo">Add Todo</button>
</div>

<script>
    wakaPAC('#app', {
        todos: [
            { text: 'Learn WakaPAC', completed: false },
            { text: 'Build an app', completed: false }
        ],

        addTodo() {
            // Array mutations automatically trigger re-render of the list
            this.todos.push({
                text: 'New todo',
                completed: false
            });
        }
    });
</script>

Objects Within Arrays

Objects stored in arrays are also wrapped in proxies, making their property changes reactive:

<div id="app">
    <div data-pac-bind="foreach: todos" data-pac-item="todo" >
        <input type="checkbox" data-pac-bind="checked: todo.completed">
        <span>{{todo.text}} (Item {{$index}})</span>
        <button data-pac-bind="click: toggleTodo">Toggle</button>
    </div>
</div>

<script>
    wakaPAC('#app', {
        todos: [
            { text: 'Task 1', completed: false },
            { text: 'Task 2', completed: false }
        ],

        toggleTodo(todo, index) {
            // Modifying object properties inside arrays triggers reactivity
            todo.completed = !todo.completed;
        }
    });
</script>

Foreach Index Variable

Within a foreach loop, WakaPAC provides the special variable $index containing the current iteration index (0-based). The $ prefix distinguishes it from user-defined properties, preventing naming conflicts.

You can customize the index variable name using the data-pac-index attribute:

<div data-pac-bind="foreach: items" data-pac-index="i">
    <span>Item {{i}}: {{item}}</span>
</div>

Reactivity Caveats

Array Index Assignment

Direct array index assignment is reactive, but sparse array assignments may not behave as expected:

// ✅ Reactive
this.todos[0] = newTodo;

// ⚠️ Creates sparse array, may not update correctly
this.todos[100] = newTodo;

Use push(), splice(), or reassign the array for complex operations.

Primitive Value Reassignment

When passing primitive values to child components or functions, changes to the original won't affect the copy:

let count = this.count;  // count is now a copy
count++;                 // this.count is unchanged

Always modify properties directly on this to maintain reactivity.