update component bindings together. WIP

pull/772/head
Rich Harris 8 years ago
parent 9b950f9ac0
commit 6366a4f55e

@ -178,6 +178,7 @@ export default function dom(
this._root = options._root || this;
this._yield = options._yield;
this._bind = options._bind;
${generator.stylesheet.hasStyles &&
options.css !== false &&

@ -45,9 +45,11 @@ export default function visitBinding(
local.bindings.push({
name: attribute.name,
value: snippet,
value: attribute.value,
snippet: snippet,
obj,
prop,
dependencies
});
const setter = getSetter({
@ -69,31 +71,33 @@ export default function visitBinding(
const observer = block.getUniqueName('observer');
const value = block.getUniqueName('value');
local.create.addBlock(deindent`
function ${observer} ( value ) {
if ( ${updating} ) return;
${updating} = true;
${setter}
${updating} = false;
}
//console.log({ setter });
${local.name}.observe( '${attribute.name}', ${observer}, { init: false });
// local.create.addBlock(deindent`
// function ${observer} ( value ) {
// if ( ${updating} ) return;
// ${updating} = true;
// ${setter}
// ${updating} = false;
// }
#component._root._beforecreate.push( function () {
var value = ${local.name}.get( '${attribute.name}' );
if ( @differs( value, ${snippet} ) ) {
${observer}.call( ${local.name}, value );
}
});
`);
// ${local.name}.observe( '${attribute.name}', ${observer}, { init: false });
local.update.addBlock(deindent`
if ( !${updating} && ${dependencies
.map(dependency => `changed.${dependency}`)
.join(' || ')} ) {
${updating} = true;
${local.name}._set({ ${attribute.name}: ${snippet} });
${updating} = false;
}
`);
// #component._root._beforecreate.push( function () {
// var value = ${local.name}.get( '${attribute.name}' );
// if ( @differs( value, ${snippet} ) ) {
// ${observer}.call( ${local.name}, value );
// }
// });
// `);
// local.update.addBlock(deindent`
// if ( !${updating} && ${dependencies
// .map(dependency => `changed.${dependency}`)
// .join(' || ')} ) {
// ${updating} = true;
// ${local.name}._set({ ${attribute.name}: ${snippet} });
// ${updating} = false;
// }
// `);
}

@ -7,6 +7,8 @@ import visitBinding from './Binding';
import visitRef from './Ref';
import { DomGenerator } from '../../index';
import Block from '../../Block';
import getTailSnippet from '../../../../utils/getTailSnippet';
import getObject from '../../../../utils/getObject';
import { Node } from '../../../../interfaces';
import { State } from '../../interfaces';
@ -149,6 +151,8 @@ export default function visitComponent(
}
const statements: string[] = [];
const name_updating = local.bindings.length && block.alias(`${name}_updating`);
if (local.bindings.length) block.addVariable(name_updating, '{}');
if (
local.staticAttributes.length ||
@ -168,11 +172,52 @@ export default function visitComponent(
local.bindings.forEach(binding => {
statements.push(
`if ( ${binding.prop} in ${binding.obj} ) ${initialData}.${binding.name} = ${binding.value};`
`if ( ${binding.prop} in ${binding.obj} ) ${initialData}.${binding.name} = ${binding.snippet};`
);
});
componentInitProperties.push(`data: ${initialData}`);
componentInitProperties.push(deindent`
_bind: function(changed, childState) {
var state = #component.get(), newState = {};
${local.bindings.map(binding => {
const { name: key } = getObject(binding.value);
if (block.contexts.has(key)) {
const prop = binding.dependencies[0];
const computed = isComputed(binding.value);
const tail = binding.value.type === 'MemberExpression' ? getTailSnippet(binding.value) : '';
return deindent`
if (changed.${binding.name}) {
var list = ${name}._context.${block.listNames.get(key)};
var index = ${name}._context.${block.indexNames.get(key)};
list[index]${tail} = childState.${binding.name};
${binding.dependencies
.map((prop: string) => `newState.${prop} = state.${prop};`)
.join('\n')}
}
`;
}
if (binding.value.type === 'MemberExpression') {
return deindent`
if (changed.${binding.name}) {
${binding.snippet} = childState.${binding.name};
${binding.dependencies.map((prop: string) => `newState.${prop} = state.${prop};`).join('\n')}
}
`;
}
return `if (changed.${key}) newState.${binding.value.name} = childState.${key};`;
})}
${name_updating} = changed;
#component._set(newState);
${name_updating} = {};
}
`);
} else if (initialProps.length) {
componentInitProperties.push(`data: ${initialPropString}`);
}
@ -188,21 +233,41 @@ export default function visitComponent(
var ${name} = new ${expression}({
${componentInitProperties.join(',\n')}
});
#component._root._beforecreate.push(function () {
var state = component.get(), newState = {};
// TODO
#component._set(newState);
});
`);
if (local.dynamicAttributes.length) {
const updates = local.dynamicAttributes.map(attribute => {
if (local.dynamicAttributes.length || local.bindings.length) {
const updates: string[] = [];
local.dynamicAttributes.forEach(attribute => {
if (attribute.dependencies.length) {
return deindent`
updates.push(deindent`
if ( ${attribute.dependencies
.map(dependency => `changed.${dependency}`)
.join(' || ')} ) ${name}_changes.${attribute.name} = ${attribute.value};
`;
`);
}
// TODO this is an odd situation to encounter I *think* it should only happen with
// each block indices, in which case it may be possible to optimise this
return `${name}_changes.${attribute.name} = ${attribute.value};`;
else {
// TODO this is an odd situation to encounter I *think* it should only happen with
// each block indices, in which case it may be possible to optimise this
updates.push(`${name}_changes.${attribute.name} = ${attribute.value};`);
}
});
local.bindings.forEach(binding => {
if (binding.dependencies.length) {
updates.push(deindent`
if ( !${name_updating}.${binding.name} && ${binding.dependencies
.map((dependency: string) => `changed.${dependency}`)
.join(' || ')} ) ${name}_changes.${binding.name} = ${binding.snippet};
`);
}
});
local.update.addBlock(deindent`
@ -233,3 +298,12 @@ export default function visitComponent(
if (!local.update.isEmpty()) block.builders.update.addBlock(local.update);
}
function isComputed(node: Node) {
while (node.type === 'MemberExpression') {
if (node.computed) return true;
node = node.object;
}
return false;
}

@ -143,6 +143,7 @@ export function _set(newState) {
this._state = assign({}, oldState, newState);
this._recompute(changed, this._state, oldState, false);
if (this._bind) this._bind(changed, this._state);
dispatchObservers(this, this._observers.pre, changed, this._state, oldState);
this._fragment.update(changed, this._state);
dispatchObservers(this, this._observers.post, changed, this._state, oldState);

@ -0,0 +1,20 @@
<p>bar in Foo: {{bar}}</p>
<p>baz in Foo: {{baz}}</p>
<script>
export default {
data() {
return {
bar: 1,
baz: 2
};
},
methods: {
double() {
const { bar, baz } = this.get();
this.set({ bar: bar * 2, baz: baz * 2 });
}
}
};
</script>

@ -0,0 +1,17 @@
export default {
test(assert, component) {
const { foo, p } = component.refs;
const values = [];
Object.defineProperty(p.childNodes[0], 'data', {
set(value) {
values.push(value);
}
});
foo.double();
assert.deepEqual(values, [6]);
}
};

@ -0,0 +1,12 @@
<Foo ref:foo bind:bar bind:baz/>
<p ref:p>{{bar + baz}}</p>
<script>
import Foo from './Foo.html';
export default {
components: {
Foo
}
};
</script>
Loading…
Cancel
Save