x-init and x-effect
Sometimes code has to run on its own rather than on an event: when a component appears on the page, or every time its data changes. The first case is handled by x-init, the second by x-effect.
x-init
The expression in x-init runs once, when Alpine starts the element:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ today: '' }" x-init="today = new Date().toLocaleDateString('en-US')">
<p>Tasks for <span x-text="today"></span></p>
</div>The list heading shows today's date. Date formatting was covered in the "Formatting with Intl" lesson of the tutorial.
The init() method
If the component's data has an init() method, Alpine calls it by itself when the component starts. This reads better than a long x-init when there is a lot of code:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{
tasks: [],
init() {
this.tasks = ['Buy milk', 'Call Oleg'];
console.log('Component started, tasks:', this.tasks.length);
}
}">
<p x-text="tasks.join(', ')"></p>
</div>The page shows two tasks, and the console under the example prints "Component started, tasks: 2". Later, init() will load data from a server.
x-effect
The expression in x-effect runs immediately and then again every time the data it reads changes. Alpine tracks which properties are used by itself:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ tasks: ['Buy milk'] }" x-effect="console.log('Tasks:', tasks.length)">
<button @click="tasks.push('New task')">Add</button>
</div>The console prints "Tasks: 1" right away, and each click prints the new number. If the expression did not read tasks, it would run only once.
Which to choose
| Task | Directive |
|---|---|
| Prepare data on start | x-init or the init() method |
| Load data from a server | The init() method |
| Repeat an action on every data change | x-effect |
| Watch one specific property | $watch, covered in a later lesson |
Common mistake
Expecting x-init to run again when data changes:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ tasks: ['Buy milk'] }" x-init="console.log('Tasks:', tasks.length)">
<button @click="tasks.push('New task')">Add</button>
</div>The console has one line, "Tasks: 1", and clicks add nothing to it: x-init runs only on start. When an action has to follow the data, use x-effect.