-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Description
This might be a wontfix (it's a niche problem, and it's very easily worked around) but I don't have time to fully investigate it right now, so just leaving myself some breadcrumbs:
<p>y: {{y}}</p>
{{#if x}}
<Foo bind:y/>
{{else}}
<Bar bind:y/>
{{/if}}
<Baz bind:x/>
<script>
import Foo from './Foo.html';
import Bar from './Bar.html';
import Baz from './Baz.html';
export default {
components: {
Foo,
Bar,
Baz
}
};
</script>
// Foo.html
<p>y: {{y}}</p>
<script>
export default {
data: () => ({
y: 'foo'
})
};
</script>
// Bar.html
<p>y: {{y}}</p>
<script>
export default {
data: () => ({
y: 'bar'
})
};
</script>
// Baz.html
<script>
export default {
data: () => ({
x: true
})
};
</script>That looks like it should result in this...
<p>y: foo</p>
<p>y: foo</p>...but in fact it ends up like this:
<p>y: undefined</p>
<p>y: foo</p>That's because on the initial pass, the {{else}} part is rendered, which initialises the binding between Main and Bar (because x doesn't yet have a value). Then, Svelte encounters the <Baz bind:x> component, and creates a new binding.
Bindings are flushed, which means that x has a value, which means that Bar is torn down (which has the effect of setting its _state to {}). Then the Bar binding is triggered, and y is set to undefined in Main.
As a starting point, no observer should be created when triggering a binding on a torn down component. (Perhaps observing a torndown component should also have no effect, or even throw — possibly a separate question.)
Changing the order of things in the template in Main.html yields different results:
<p>y: {{y}}</p>
<Baz bind:x/>
{{#if x}}
<Foo bind:y/>
{{else}}
<Bar bind:y/>
{{/if}}<p>y: bar</p>
<p>y: bar</p>(bar and not foo because by the time <Foo bind:y/> is created, y has a value in the parent component, and the child won't override the parent. Removing the phantom observer would presumably fix that as well.)