Avoid conflicting state between Alpine Components
In Hyvä, global functions are primarily used to initialize Alpine.js components.
Avoid conflict prone names
When declaring global functions, choose names that are unlikely to cause conflicts.
For example, init() is a poor choice. A more robust name like myCompanyMyModuleThisComponentInit() significantly reduces conflict risk.
Initializing component state
Alpine.js initialization methods return objects.
The returned state is typically not shared, allowing it to be reused across multiple Alpine.js components (e.g., for a selection of products on a page).
For example:
<script>
function initMyComponent() {
return {
isVisible: true,
toggleVisibility() {
this.isVisible = ! this.isVisible;
}
};
}
</script>
<h2 x-data="initMyComponent()">
<button @click="toggleVisibility">A</button>
<span x-show="isVisible">AAA</span>
</h2>
<h2 x-data="initMyComponent()">
<button @click="toggleVisibility">B</button>
<span x-show="isVisible">BBB</span>
</h2>
As shown, each component instance maintains its own state, allowing independent visibility changes.
Using a unique method name suffix
When components need instance-specific data (e.g., a product ID), managing state becomes more complex.
One solution is to append a unique suffix to each component's initialization method name:
<?php $uniqueId = uniqid(); ?>
<script>
function initMyComponent_<?= $uniqueId ?>() {
return {
productId: <?= $product->getId() ?>,
// more code
};
}
</script>
<div x-data="initMyComponent_<?= $uniqueId ?>()">
more code
</div>
Here, PHP renders instance-specific data directly into the returned object, ensuring each component has its unique state.
Warning
Use unique components cautiously. They increase DOM size due to duplication and should only be used when essential.
Passing values to the initialization function
A better alternative is to pass instance-specific data as an argument to the initialization method:
<script>
function initMyComponent(config) {
return {
productId: config.productId,
// more code
};
}
</script>
<div x-data="initMyComponent({productId: <?= $product->getId() ?>})">
more code
</div>
This allows the initialization function to be re-used with different values.
If the function contains significant shared logic, this approach is preferred as the function is rendered only once.
If the code primarily consists of item-specific values, either approach works.