Creating non-reactive property in child init breaks scope rules #4689
-
|
Hi friends, Apologies if this is working as expected, but my understanding is each component's init is supposed be scoped to the instance. I would expect creating a new property inside init would bind it to the component instance and not share scope with any other object. However in this minimal example, If I remove the parent component, the problem goes away and both component instances maintain their own scope. It looks like the the original assignment is binding the value to the shared parent scope and not the current component. This breaks my mental model of how Alpine's init works. I would expect a shared parent's properties to be readable in both children, but I wouldn't expect assigning the property inside a child to overwrite sibling's data. If I make the The below is a minimal reproduction of the issue taken from a larger dropdown component I was working on. <script>
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
_isActive: true,
get isActive() {
return this._isActive;
},
init() {
this.$nextTick(() => {
this._originalButtonHref = this.$refs.button.href;
console.log('init:', this._originalButtonHref);
});
},
toggleButton: {
['x-effect']() {
const originalHref = this._originalButtonHref;
console.log('X-Effect:', this, originalHref);
if (originalHref) {
const button = this.$refs.button;
if (this.isActive) {
button.href = '#';
} else {
button.href = originalHref;
}
}
},
['x-ref']: 'button',
},
}))
})
</script>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
<nav>
<ul class="parent" x-data>
<li x-data="dropdown">
<a x-bind="toggleButton" href="first">First Nav Toggle></a>
<ul x-cloak x-show="isActive">
<li>
<a>Sub Nav</a>
</li>
</ul>
</li>
<li x-data="dropdown">
<a x-bind="toggleButton" href="second">Second Nav Toggle</a>
<ul x-cloak x-show="isActive">
<li>
<a>Sub Nav <span></span></a>
</li>
</ul>
</li>
</ul>
</nav> |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
|
Since the component in question doesn't have it added at all, it's actually adding it to the parent, and not the sibling. So the one that runs first tries to find it, can't and so updates the parent, and the second sees it on the parent and updates that. Generally speaking, if you want a component to scope a key, you need to put that key on that component. also, the property is still reactive. Even properties added after the fact are reactive. I don't know why the original implementation of the merged datastack defaulted to assigning to the top of the stack and not the bottom, but I just tried to maintain that behavior when I refactored it all. |
Beta Was this translation helpful? Give feedback.
Since the component in question doesn't have it added at all, it's actually adding it to the parent, and not the sibling.
So the one that runs first tries to find it, can't and so updates the parent, and the second sees it on the parent and updates that.
Generally speaking, if you want a component to scope a key, you need to put that key on that component.
also, the property is still reactive. Even properties added after the fact are reactive.
I don't know why the original implementation of the merged datastack defaulted to assigning to the top of the stack and not the bottom, but I just tried to maintain that behavior when I refactored it all.