Type of Change
Feature
Summary
Building off the outcome of #87 , would like to, and have already started playing around with, a more "fine grained" observability model; one that doesn't require an entire re-render and blowing out innerHTML, but can instead more acutely update DOM nodes (textContent, setAttribute) instead.
Details
So for example, taking our Counter component
export default class Counter extends HTMLElement {
...
render() {
const { count } = this;
return (
<div>
<button onclick={this.count -= 1}> -</button>
<span>You have clicked <span class="red">{count}</span> times</span>
<button onclick={this.count += 1}> +</button>
</div>
);
}
}
Which would produce this compiled output
export default class Counter extends HTMLElement {
static get observedAttributes() {
return ['count'];
}
attributeChangedCallback(name, oldValue, newValue) {
function getValue(value) {
return value.charAt(0) === '{' || value.charAt(0) === '[' ? JSON.parse(value) : !isNaN(value) ? parseInt(value, 10) : value === 'true' || value === 'false' ? value === 'true' ? true : false : value;
}
if (newValue !== oldValue) {
switch (name) {
case 'count':
this.count = getValue(newValue);
break;
}
this.render();
}
}
...
}
Instead, we would want the compiled output to look something like this instead
export default class Counter extends HTMLElement {
static get observedAttributes() {
return ['count'];
}
attributeChangedCallback(name, oldValue, newValue) {
function getValue(value) {
return value.charAt(0) === '{' || value.charAt(0) === '[' ? JSON.parse(value) : !isNaN(value) ? parseInt(value, 10) : value === 'true' || value === 'false' ? value === 'true' ? true : false : value;
}
if (newValue !== oldValue) {
switch (name) {
case 'count':
this.count = getValue(newValue);
break;
}
this.update(name, oldValue, newValue);
}
}
update(name, oldValue, newValue) {
const attr = \`data-wcc-\${name}\`;
const selector = \`[\${attr}]\`;
this.querySelectorAll(selector).forEach((el) => {
const needle = oldValue || el.getAttribute(attr);
switch(el.getAttribute('data-wcc-ins')) {
case 'text':
el.textContent = el.textContent.replace(needle, newValue);
break;
case 'attr':
if (el.hasAttribute(el.getAttribute(attr))) {
el.setAttribute(el.getAttribute(attr), newValue);
}
break;
}
})
}
...
}
Additional Thoughts:
- It might stand to reason we should map updates back to attributes, to keep things in sync? But not sure if this co-mingling is good or bad? Probably if state is meant to go "out" it should be done through custom events instead? Will need to play around with this a bit
- Would be good to explore tagged template functions as part of this, if not for at least the underlying templating mechanics (as opposed to instead of using JSX directly)
- Although we only scan the
render function for this references, would we do ourselves a service by scanning constructor too, maybe for init values and / or something related to SSR?
- Not sure if
dataset could be useful for anything?
Type of Change
Feature
Summary
Building off the outcome of #87 , would like to, and have already started playing around with, a more "fine grained" observability model; one that doesn't require an entire re-render and blowing out
innerHTML, but can instead more acutely update DOM nodes (textContent,setAttribute) instead.Details
So for example, taking our Counter component
Which would produce this compiled output
Instead, we would want the compiled output to look something like this instead
Additional Thoughts:
renderfunction forthisreferences, would we do ourselves a service by scanningconstructortoo, maybe for init values and / or something related to SSR?datasetcould be useful for anything?