first stab at auto-subscriptions

pull/1880/head
Rich Harris 7 years ago
parent 48f1f6b4d0
commit a3e95c7b10

@ -882,7 +882,12 @@ export default class Component {
} }
warn_if_undefined(node, template_scope: TemplateScope, allow_implicit?: boolean) { warn_if_undefined(node, template_scope: TemplateScope, allow_implicit?: boolean) {
const { name } = node; let { name } = node;
if (allow_implicit && name[0] === '$') {
name = name.slice(1);
this.has_reactive_assignments = true;
}
if (allow_implicit && !this.instance_script) return; if (allow_implicit && !this.instance_script) return;
if (this.instance_scope && this.instance_scope.declarations.has(name)) return; if (this.instance_scope && this.instance_scope.declarations.has(name)) return;

@ -118,7 +118,7 @@ export default class Expression {
// conditions — it doesn't apply if the dependency is inside a // conditions — it doesn't apply if the dependency is inside a
// function, and it only applies if the dependency is writable // function, and it only applies if the dependency is writable
if (component.instance_script) { if (component.instance_script) {
if (component.writable_declarations.has(name)) { if (component.writable_declarations.has(name) || name[0] === '$') {
dynamic_dependencies.add(name); dynamic_dependencies.add(name);
} }
} else { } else {

@ -257,11 +257,15 @@ export default function dom(
return true; return true;
}); });
const reactive_stores = Array.from(component.template_references).filter(n => n[0] === '$');
filtered_declarations.push(...reactive_stores);
const has_definition = ( const has_definition = (
component.javascript || component.javascript ||
filtered_props.length > 0 || filtered_props.length > 0 ||
component.partly_hoisted.length > 0 || component.partly_hoisted.length > 0 ||
filtered_declarations.length > 0 || filtered_declarations.length > 0 ||
reactive_stores.length > 0 ||
component.reactive_declarations.length > 0 component.reactive_declarations.length > 0
); );
@ -280,6 +284,13 @@ export default function dom(
: null : null
); );
const reactive_store_subscriptions = reactive_stores
.map(name => deindent`
let ${name};
$$self.$$.on_destroy.push(${name.slice(1)}.subscribe($$value => { ${name} = $$value; $$make_dirty('${name}'); }));
`)
.join('\n\n');
if (has_definition) { if (has_definition) {
builder.addBlock(deindent` builder.addBlock(deindent`
function ${definition}(${args.join(', ')}) { function ${definition}(${args.join(', ')}) {
@ -287,6 +298,8 @@ export default function dom(
${component.partly_hoisted.length > 0 && component.partly_hoisted.join('\n\n')} ${component.partly_hoisted.length > 0 && component.partly_hoisted.join('\n\n')}
${reactive_store_subscriptions}
${filtered_declarations.length > 0 && `$$self.$$.get = () => (${stringifyProps(filtered_declarations)});`} ${filtered_declarations.length > 0 && `$$self.$$.get = () => (${stringifyProps(filtered_declarations)});`}
${set && `$$self.$$.set = ${set};`} ${set && `$$self.$$.set = ${set};`}

@ -36,6 +36,9 @@ export default function ssr(
user_code = `let { ${props.join(', ')} } = $$props;` user_code = `let { ${props.join(', ')} } = $$props;`
} }
const reactive_stores = Array.from(component.template_references).filter(n => n[0] === '$');
const reactive_store_values = reactive_stores.map(name => `const ${name} = @get_store_value(${name.slice(1)});`)
// TODO only do this for props with a default value // TODO only do this for props with a default value
const parent_bindings = component.javascript const parent_bindings = component.javascript
? component.props.map(prop => { ? component.props.map(prop => {
@ -51,6 +54,8 @@ export default function ssr(
do { do {
$$settled = true; $$settled = true;
${reactive_store_values}
${component.reactive_declarations.map(d => d.snippet)} ${component.reactive_declarations.map(d => d.snippet)}
$$rendered = \`${renderer.code}\`; $$rendered = \`${renderer.code}\`;
@ -59,6 +64,8 @@ export default function ssr(
return $$rendered; return $$rendered;
` `
: deindent` : deindent`
${reactive_store_values}
${component.reactive_declarations.map(d => d.snippet)} ${component.reactive_declarations.map(d => d.snippet)}
return \`${renderer.code}\`;`; return \`${renderer.code}\`;`;

@ -98,3 +98,9 @@ export function create_ssr_component($$render) {
$$render $$render
}; };
} }
export function get_store_value(store) {
let value;
store.subscribe(_ => value = _)();
return value;
}

@ -0,0 +1,28 @@
import { writable } from '../../../../store.js';
export default {
props: {
count: writable(0)
},
html: `
<button>count 0</button>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
const click = new window.MouseEvent('click');
await button.dispatchEvent(click);
assert.htmlEqual(target.innerHTML, `
<button>count 1</button>
`);
await component.count.set(42);
assert.htmlEqual(target.innerHTML, `
<button>count 42</button>
`);
}
};

@ -0,0 +1,6 @@
<script>
export let count;
let double;
</script>
<button on:click="{() => count.update(n => n + 1)}">count {$count}</button>
Loading…
Cancel
Save