Reactivity System Deep Dive
Understand how Alpine uses Proxies for reactivity.
How Reactivity Works
Alpine's reactivity is based on JavaScript Proxies. When you define data via x-data or Alpine.reactive(), Alpine wraps your object in a Proxy that intercepts property access and mutations. This allows Alpine to track exactly which properties are used in which effects and update only the necessary parts of the DOM.
Creating Reactive Objects Manually
const raw = { count: 0 }
const state = Alpine.reactive(raw)
Alpine.effect(() => {
console.log(state.count)
})
state.count++ // automatically triggers the effect and logs 1Array Reactivity
Alpine intercepts common array mutation methods (push, pop, splice, shift, unshift, sort, reverse). However, setting an item by index (arr[0] = 'new') is not reactive. Use splice(index, 1, newValue) instead.
Getting the Raw Object
Sometimes you need the underlying plain object (e.g., to send to an API). Use Alpine.raw() to unwrap the reactive proxy.
const plainObject = Alpine.raw(reactiveState)
JSON.stringify(plainObject) // safe, no circular referencesReactivity Outside Components
You can create standalone reactive objects that are not tied to any component. This is how stores work under the hood, and it's useful for managing global state.
const appState = Alpine.reactive({
isLoading: false,
user: null
})
// Use in any Alpine.effect() or component💡 Tip
If you need to watch deeply nested objects, consider using $watch with the deep flag, or structure your data so that you replace whole objects rather than mutating deep properties.