Last active
October 2, 2019 19:38
-
-
Save maparent/9565cf0b504ed47ae719aca74c182617 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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