Description: The x-effect directive in AlpineJS allows you to automatically re-run a JavaScript expression or a component method whenever any of its dependent reactive data properties change. This is particularly useful for implementing "side effects" – actions that need to occur in response to data modifications but don't necessarily produce a value for direct display (e.g., saving data to localStorage, logging to the console, or triggering other non-UI updates).
x-effect="expressionOrMethodCall()"
x-data).x-data) that are accessed inside this expression or method during its execution.<div x-data="{ userName: 'Alex', messageCount: 0 }">
<div x-effect="console.log('User:', userName, 'Messages:', messageCount)"></div>
<!-- This will log to console on init, and whenever userName or messageCount changes -->
</div>
Alpine automatically tracks dependencies within the expression.
x-effect should "watch." Alpine determines this by observing which reactive data properties are read during the execution of the x-effect's code.x-effect="document.title = pageTitle + ' - ' + siteName", Alpine understands that it needs to re-run this effect if either pageTitle or siteName (assuming they are reactive properties in your component) changes.Creating infinite loops with x-effect:
x-effect expression modifies a data property that it also depends on (i.e., reads), it can create an infinite loop. The effect runs, changes the data, which then triggers the effect to run again, and so on.// In an Alpine component: x-data="{ count: 0 }"
// HTML: <div x-effect="count++"></div>
// This creates an infinite loop because 'count++' both reads and modifies 'count'.
$watch might be a better tool if you need more control over the update, or if the logic is complex.Misunderstanding dependency tracking:
x-effect only re-runs if properties directly accessed (read) within its expression (or methods called by it) change. If a dependency is obscured (e.g., through highly indirect calls, or conditional logic that prevents access on some runs), the effect might not re-run as expected.x-effect="console.log(this.user.name)". Alpine knows this.user.name is a dependency.x-effect="myMethod()", where myMethod() { console.log(this.user.name); }. Alpine typically traces through synchronous method calls.myMethod() has complex branching logic and only sometimes accesses this.user.name, or if dependencies are determined by non-reactive external variables, tracking might be less predictable.watchEffect nuances but still requires careful thought about what data is being read.Using x-effect for tasks better suited to $watch or derived data:
x-effect: Best for side effects that need to run whenever any of its (often multiple) dependencies change. You don't inherently get old/new values of a specific changed property. It's about performing an action.
$watch('propertyName', (newValue, oldValue) => { ... }): Use this when you need to react to changes in a specific data property and often need to compare its oldValue and newValue to make decisions. It offers more granular control for specific property observation.
x-data): If you simply need a value that is automatically computed based on other data properties (e.g., a fullName from firstName and lastName), use a getter function within your x-data object. This isn't a side effect; it's a computed value primarily for display or use in other logic.
Alpine.data('myComponent', () => ({
firstName: 'Jane',
lastName: 'Doe',
get fullName() {
return this.firstName + ' ' + this.lastName;
}
}));
// In HTML: <span x-text="fullName"></span>
x-effect, consider if your goal is a general side effect, a reaction to a specific property with access to old/new values, or just a computed value. Choosing the right tool makes your component logic clearer and more maintainable.
Form data is automatically saved to localStorage approx. 500ms after you stop typing. This is handled by x-effect.
Last saved:
Open your browser's developer console to see x-effect logs.