Skip to content

Instantly share code, notes, and snippets.

@maparent
Last active October 2, 2019 19:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maparent/9565cf0b504ed47ae719aca74c182617 to your computer and use it in GitHub Desktop.
Save maparent/9565cf0b504ed47ae719aca74c182617 to your computer and use it in GitHub Desktop.
import app, { Component, EventOptions } from 'apprun';
function doChildEv(ev: Event) {
this._component.run("childSetState", ev);
}
function getComponent(el) {
while (el) {
if (el && el._component) {
return el._component
}
el = el.parentElement
}
}
export class CompositeComponent extends Component {
public setState(state, options: EventOptions
= { render: true, history: false}) {
super.setState(state, options);
if (state) {
if (!(state instanceof Promise)) {
var element = document.getElementById(this.element)
if (element) {
element.parentElement.dispatchEvent(new CustomEvent('childSetStateD', {detail: this, bubbles: true}));
}
}
}
}
render(element: HTMLElement, node) {
super.render(element, node)
// use a named function to avoid listener duplication
element.addEventListener("childSetStateD", doChildEv)
}
}
export class TreeComponent extends CompositeComponent {
view = (state) => {
var li = <li>
{state.num}
 <button onclick={() => this.run("-1")}>-1</button>
      <button onclick={() => this.run("+1")}>+1</button>
</li>;
if (state['sub']) {
li.children.push(<ul>
{state.sub.map((childState)=> app.createElement(TreeComponent, childState))}
</ul>)
}
return li
}
  update = {
    '+1': (state) => {
var sub = state.sub?state.sub.slice():[]
sub.push({"id": `_${Date.now()}`, "num": state.num + "." + (sub.length+1), "sub": []})
return {...state, sub}
},
    '-1': (state) => {
var sub = state.sub || []
var len = sub.length
if (len) {
sub = sub.slice(0, len-1)
}
return {...state, sub}
},
childSetState: (state, event) => {
event.stopPropagation()
if (state === undefined)
return
const child = event.detail
const childState = {...child.state}
// if the element was rendered, children was added to props in
// https://github.com/yysun/apprun/blob/5be47db699c513690377e03bc40410a4ac9bf2f0/src/createComponent.tsx#L12
// so remove it here. Otherwise, besides spurious updates,
// we'll get a bug when children is assigned as a prop in
// https://github.com/yysun/apprun/blob/e4ef0c7658320f9ec314e862221c16a46a6f0c3b/src/vdom-my.ts#L189
delete childState.children
const child_id = child.state.id // could use child.element
const sub = state.sub.slice()
const idx = sub.findIndex((substate)=>substate.id == child_id)
if (idx >= 0 && childState != sub[idx]) {
// avoid loop with deep compare
if (JSON.stringify(childState) === JSON.stringify(sub[idx])) {
return
}
sub.splice(idx, 1, childState)
return {...state, sub}
}
}
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment