only recreate when the expression value changed

pull/5397/head
Tan Li Hau 5 years ago
parent a0f0e8ad67
commit e3112a4711

@ -30,12 +30,16 @@ export default class KeyBlockWrapper extends Wrapper {
this.dependencies = node.expression.dynamic_dependencies();
this.block = block.child({
if (this.dependencies.length) {
block = block.child({
comment: create_debugging_comment(node, renderer.component),
name: renderer.component.get_unique_name("create_key_block"),
type: "key"
});
renderer.blocks.push(block);
}
this.block = block;
this.fragment = new FragmentWrapper(
renderer,
this.block,
@ -44,11 +48,21 @@ export default class KeyBlockWrapper extends Wrapper {
strip_whitespace,
next_sibling
);
renderer.blocks.push(this.block);
}
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
if (this.dependencies.length === 0) {
this.render_static_key(block, parent_node, parent_nodes);
} else {
this.render_dynamic_key(block, parent_node, parent_nodes);
}
}
render_static_key(_block: Block, parent_node: Identifier, parent_nodes: Identifier) {
this.fragment.render(this.block, parent_node, parent_nodes);
}
render_dynamic_key(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
this.fragment.render(
this.block,
null,
@ -60,6 +74,13 @@ export default class KeyBlockWrapper extends Wrapper {
);
const dynamic = this.block.has_update_method;
const previous_key = block.get_unique_name('previous_key');
const snippet = this.node.expression.manipulate(block);
block.add_variable(previous_key, snippet);
const not_equal = this.renderer.component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`;
const condition = x`${this.renderer.dirty(this.dependencies)} && ${not_equal}(${previous_key}, ${previous_key} = ${snippet})`;
block.chunks.init.push(b`
let ${this.var} = ${this.block.name}(#ctx);
`);
@ -73,8 +94,6 @@ export default class KeyBlockWrapper extends Wrapper {
});`
);
const anchor = this.get_or_create_anchor(block, parent_node, parent_nodes);
if (this.dependencies.length) {
const body = b`
${
has_transitions
@ -93,7 +112,7 @@ export default class KeyBlockWrapper extends Wrapper {
if (dynamic) {
block.chunks.update.push(b`
if (${this.renderer.dirty(this.dependencies)}) {
if (${condition}) {
${body}
} else {
${this.var}.p(#ctx, #dirty);
@ -101,14 +120,11 @@ export default class KeyBlockWrapper extends Wrapper {
`);
} else {
block.chunks.update.push(b`
if (${this.renderer.dirty(this.dependencies)}) {
if (${condition}) {
${body}
}
`);
}
} else if (dynamic) {
block.chunks.update.push(b`${this.var}.p(#ctx, #dirty);`);
}
if (has_transitions) {
block.chunks.intro.push(b`@transition_in(${this.var})`);

@ -0,0 +1,14 @@
// with reactive content beside `key`
export default {
html: `<div>00</div>`,
async test({ assert, component, target, window }) {
const div = target.querySelector('div');
component.reactive = 2;
assert.htmlEqual(target.innerHTML, `<div>02</div>`);
assert.strictEqual(div, target.querySelector('div'));
component.value = 5;
assert.htmlEqual(target.innerHTML, `<div>52</div>`);
assert.notStrictEqual(div, target.querySelector('div'));
}
};

@ -0,0 +1,8 @@
<script>
export let value = 0;
export let reactive = 0;
</script>
{#key value}
<div>{value}{reactive}</div>
{/key}

@ -0,0 +1,15 @@
export default {
html: `<div>1</div>`,
async test({ assert, component, target, window }) {
let div = target.querySelector("div");
await component.append(2);
assert.htmlEqual(target.innerHTML, `<div>1</div>`);
assert.strictEqual(div, target.querySelector("div"));
div = target.querySelector("div");
component.array = [3, 4];
assert.htmlEqual(target.innerHTML, `<div>3,4</div>`);
assert.notStrictEqual(div, target.querySelector("div"));
}
};

@ -0,0 +1,14 @@
<svelte:options immutable />
<script>
export let array = [1];
export function append(value) {
array.push(value);
array = array;
}
</script>
{#key array}
<div>{array.join(',')}</div>
{/key}

@ -0,0 +1,15 @@
export default {
html: `<div>1</div>`,
async test({ assert, component, target, window }) {
let div = target.querySelector("div");
await component.append(2);
assert.htmlEqual(target.innerHTML, `<div>1,2</div>`);
assert.notStrictEqual(div, target.querySelector("div"));
div = target.querySelector("div");
component.array = [3, 4];
assert.htmlEqual(target.innerHTML, `<div>3,4</div>`);
assert.notStrictEqual(div, target.querySelector("div"));
}
};

@ -0,0 +1,12 @@
<script>
export let array = [1];
export function append(value) {
array.push(value);
array = array;
}
</script>
{#key array}
<div>{array.join(',')}</div>
{/key}

@ -0,0 +1,18 @@
export default {
html: `<div>3</div>`,
async test({ assert, component, target, window }) {
const div = target.querySelector("div");
await component.mutate();
assert.htmlEqual(target.innerHTML, `<div>5</div>`);
assert.strictEqual(div, target.querySelector("div"));
await component.reassign();
assert.htmlEqual(target.innerHTML, `<div>7</div>`);
assert.strictEqual(div, target.querySelector("div"));
await component.changeKey();
assert.htmlEqual(target.innerHTML, `<div>7</div>`);
assert.notStrictEqual(div, target.querySelector("div"));
}
};

@ -0,0 +1,17 @@
<script>
let obj = { key: 1, value: 3 };
export function mutate() {
obj.value = 5;
}
export function reassign() {
obj = { key: 1, value: 7 };
}
export function changeKey() {
obj.key = 3;
}
</script>
{#key obj.key}
<div>{obj.value}</div>
{/key}

@ -0,0 +1,28 @@
export default {
html: `<div>000</div>`,
async test({ assert, component, target, window }) {
let div = target.querySelector("div");
component.value = 2;
assert.htmlEqual(target.innerHTML, `<div>200</div>`);
assert.notStrictEqual(div, target.querySelector("div"));
div = target.querySelector("div");
component.anotherValue = 5;
assert.htmlEqual(target.innerHTML, `<div>250</div>`);
assert.notStrictEqual(div, target.querySelector("div"));
div = target.querySelector("div");
component.thirdValue = 9;
assert.htmlEqual(target.innerHTML, `<div>259</div>`);
assert.strictEqual(div, target.querySelector("div"));
// make dirty while maintain the value of `value + anotherValue`
// should update the content, but not recreate the elements
await component.$set({ value: 4, anotherValue: 3 });
assert.htmlEqual(target.innerHTML, `<div>439</div>`);
assert.strictEqual(div, target.querySelector("div"));
}
};

@ -4,6 +4,6 @@
export let thirdValue = 0;
</script>
{#key [value, anotherValue]}
{#key value + anotherValue}
<div>{value}{anotherValue}{thirdValue}</div>
{/key}

@ -1,21 +0,0 @@
export default {
html: `<div>000</div>`,
async test({ assert, component, target, window }) {
let div = target.querySelector('div');
component.value = 2;
assert.htmlEqual(target.innerHTML, `<div>200</div>`);
assert.notStrictEqual(div, target.querySelector('div'));
div = target.querySelector('div');
component.anotherValue = 5;
assert.htmlEqual(target.innerHTML, `<div>250</div>`);
assert.notStrictEqual(div, target.querySelector('div'));
div = target.querySelector('div');
component.thirdValue = 9;
assert.htmlEqual(target.innerHTML, `<div>259</div>`);
assert.strictEqual(div, target.querySelector('div'));
}
};

@ -1,13 +1,17 @@
export default {
html: `<div>00</div>`,
html: `<div>0</div><div>0</div>`,
async test({ assert, component, target, window }) {
const div = target.querySelector('div');
component.reactive = 2;
assert.htmlEqual(target.innerHTML, `<div>02</div>`);
assert.strictEqual(div, target.querySelector('div'));
let [div1, div2] = target.querySelectorAll('div');
component.value = 5;
assert.htmlEqual(target.innerHTML, `<div>52</div>`);
assert.notStrictEqual(div, target.querySelector('div'));
assert.htmlEqual(target.innerHTML, `<div>5</div><div>0</div>`);
assert.notStrictEqual(div1, target.querySelectorAll('div')[0]);
assert.strictEqual(div2, target.querySelectorAll('div')[1]);
[div1, div2] = target.querySelectorAll('div');
component.reactive = 10;
assert.htmlEqual(target.innerHTML, `<div>5</div><div>10</div>`);
assert.strictEqual(div1, target.querySelectorAll('div')[0]);
assert.strictEqual(div2, target.querySelectorAll('div')[1]);
}
};

@ -4,5 +4,7 @@
</script>
{#key value}
<div>{value}{reactive}</div>
<div>{value}</div>
{/key}
<div>{reactive}</div>
Loading…
Cancel
Save