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

Code
const raw = { count: 0 }
const state = Alpine.reactive(raw)

Alpine.effect(() => {
  console.log(state.count)
})
state.count++ // automatically triggers the effect and logs 1

Array 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.

Code
const plainObject = Alpine.raw(reactiveState)
JSON.stringify(plainObject) // safe, no circular references

Reactivity 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.

Code
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.

Helpful? Share this page!↑ Back to top