Closed dy closed 4 years ago
What's the elegant way, instead of wrapping rendering into loop and wrapping field into observable?
Ideally it is easily upgradable from simple field (static → dynamic).
a
+ map
is pretty good tbh:
fx(el.props, props => h`<${el}>${ props.data.map(item => h`<a>${ item.title }</a>`) }</>`)
// a + map
h`<${el}>${ a(el, 'data').map(data => data.map(item => h`<a>${item.title}</a>`) }</>`
// f
h`<${el}>${ f(a(el, 'data'), data => data.map(item => h`<a>${item.title}</a>`)) }</>`
// a as v
h`<${el}>${ a(el, 'data', data => data.map(item => h`<a>${item.title}</a>`)) }</>`
// map operator
h`<${el}>${ map(data => data.map(item => h`<a>${item.title}</a>`))(a(el, 'data')) }</>`
Map operator alleviates situation with stuffing everything into v
. In fact, v
can be moved to state
in strui, along with map
, from
, fx
, calc
, input
, attr
and others.
h
can be moved out too - xhtm? So $
leaves only as aspect connector, basically spect@13, super-performant. Alternatively, selector collections, if make sense.
The question is about h
and v`a${b}c`
- they seem to be out of strui scope. v
is not 100% stream or subject, it is value container, streamable though. Moving any-case observer stuff from v
to strui/from
, and keeping v
thin (sube
-covering only) features it's value container nature, emphasizing spect
uniqueness.
$
aspect-binder only, no collections.v
minimal value container, with safest available streams: observable, async iterable (sube). No grouping, no calc, no map.h
a hyperscript with observables: likely level up htm in xhtm.A downside of turning down groups from v:
v`a${obs}b`
becomes impossiblegroup
, nor calc
, nor source
. Is that possible to resurrect Proxy-based v function wrapper, by default acting as an object, but callable? It could be just transparent observable layer, exposing all internal prototype props, so that the only drawback would be tainted direct primitive values #64, #160, #182. That is possible to make it be transparent for object/array data.
Transparent observable any-value wrapper can distinguish spect/v
from regular observable tech, which follows the element-props
practice (nice & short). Not even sure if it needs to be a function, mb for get/set:
let x = v(1), y = v(2)
h`sum: ${ x + y }` //static
h`sum: ${ map((x, y) => )(x, y) }` //dynamic + strui
h`sum: ${ x[Symbol.observable]().map(x => x + y) } //dynamic symbol
h`sum: ${ x.map(x => x + y) } //dynamic self - it is observable too!
h`sum: ${ v(x, y).map((x, y) => x + y) }` //dynamic group observable (no obj/array yay)
Get/set:
let x = v(init)
≈ x(reinit)
≈ useState(init)
≈ setState(reinit)
, this way function is the only special clause of v:
let x = v(1), y = v(2), sum = v(x, y).map((x, y) => x + y)
// or (x, y) |> map((x, y) => x + y) with n-ary pipelines + strui
x(2), +sum // 4
// fn observable is the only exception - like dynamic method
let fn = v(() => fn)
fn(...args) // direct call
fn(() => fn2) // reinit
Tbh mixing in value props into observable looks a bit messy, esp. in case of map. It is useful to have observable storage, yes, but it feels like observable level should be in a different plane, behind Symbol.observable
, that makes v
not real observable instance, but observable-compatible (not necessarily bad). Also that raises question of mapping:
v(a, b, c) // no map possible - what's use from this group?
abc = v([a, b, c]) // not real group, but array value, items are not observed
abc[0] // first item, not observable
abc = v({a, b, c}) // not group, but dict. Each value is not observed
abc.a // a item, not observable
// ... too many downsides
// would be useful to have, for example, group:
abc = v(a, b, c) // observable of multiple items
abc.map((a,b,c) => a + b + c) // simple observable result
abc() // get value - what?? multiple returns are not possible in js, only webassembly
abc(a1, b1, c1) // set new value
So considering that ↑ confusion, v
better be regular observable channel, as so:
v(el.props).map(({select}) => select ? select.map(...) : default)
Exposing internal props doesn't have much use and rather perplex things.
So there are essentially 3 separate concerns: calc/group, value container (channel), object/array observable proxy.
Not sure about selector-collection - little implementational difference from only-aspects, they come at very low price. The rest is implemented in v22.
Now v is subscribe, calc and transform. Can be confusing sometimes. Splitting it to
f
forfx
andv
forvalue
makes code cleaner and internal aspects code flow more pleasant, along withel.props
for element properties. That pivots from$
,h
,v
...The purpose of
f
is subscribing to changes ina
, can be useful for organizing rendering/updating loops triggered by deps.Also - likely re-rendering full tree in fx is not expensive, since it's cached.
That removes need in mapping observables, and essentially makes optional for
h
to take in observables.