mirror of https://github.com/sveltejs/svelte
fix: ensure custom element attribute/prop changes are in their own context (#14016)
Fixes #13848. When we set custom element attributes/props, we should be doing so without the current effect/reaction active. Otherwise, the custom element lifecycle might attach effects/dependencies to the wrong reaction and all manner of things can incorrectly occur --------- Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>pull/14056/head
parent
4c6255f8dd
commit
cdec39afac
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'svelte': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
fix: ensure custom element attribute/prop changes are in their own context
|
@ -0,0 +1,24 @@
|
|||||||
|
import { test } from '../../assert';
|
||||||
|
const tick = () => Promise.resolve();
|
||||||
|
|
||||||
|
export default test({
|
||||||
|
async test({ assert, target }) {
|
||||||
|
target.innerHTML = '<my-app/>';
|
||||||
|
await tick();
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
/** @type {any} */
|
||||||
|
const el = target.querySelector('my-app');
|
||||||
|
const button = el.shadowRoot.querySelector('button');
|
||||||
|
const p = el.shadowRoot.querySelector('my-tracking').shadowRoot.querySelector('p');
|
||||||
|
|
||||||
|
assert.equal(button.innerHTML, '0');
|
||||||
|
assert.equal(p.innerHTML, 'false');
|
||||||
|
|
||||||
|
button.click();
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
assert.equal(button.innerHTML, '1');
|
||||||
|
assert.equal(p.innerHTML, 'false');
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,31 @@
|
|||||||
|
<svelte:options customElement="my-app" />
|
||||||
|
|
||||||
|
<script module>
|
||||||
|
class Tracking extends HTMLElement {
|
||||||
|
static observedAttributes = ["count"];
|
||||||
|
tracking = false;
|
||||||
|
|
||||||
|
set count(_) {
|
||||||
|
this.tracking = $effect.tracking();
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.attachShadow({ mode: 'open' });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.shadowRoot.innerHTML = `<p>${this.tracking}</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("my-tracking", Tracking);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let count = $state(0);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button onclick={() => (count += 1)}>{count}</button>
|
||||||
|
<my-tracking {count}></my-tracking>
|
Loading…
Reference in new issue