Fragments don't support reactive values
Opened this issue ยท 26 comments
Here is the example code.
https://stackblitz.com/edit/vitejs-vite-a8hsjs?file=main.jsx
To understand the pain point:
You expect observables returned from component to work dynamically, right?
Like let A = () => count; h(A)
Ok, try v1.3.2 - must subscribe to observables returned from components.
Note only that these observables can generate only text. If components return real elements, they're considered static.
https://stackblitz.com/edit/vitejs-vite-qypzhx?file=main.jsx
@dy Still I see an issue on live fragments. Can you check the above code?
Just want to make sure what's the value of the proposed feature? Is that curiosity / theoretical purity or you have practical / useful scenario?
The path of implementing full dynamicity is prone to complexities and problematic debugging - document fragments remove its children once being inserted, tracking document fragments within document fragments seems to be shaky.
@dy Really sorry to bother with this.
Only curiosity. Just thinking to convert my existing React app with this. I have many components which return fragments and updates dynamically. I just tried with solidjs it's working as expected. https://stackblitz.com/edit/vitejs-vite-4bxibo?file=src%2FApp.tsx
Right, solid builds virtual dom and renders it, as classic vdom libs do.
Hyperf just builds (little) reactive fragments. I wonder isn't that too magical if such fragments, being inserted somewhere, bring dynamicity like updating DOM it had nothing to do with initially. Text nodes are fine to be updated, they don't change the DOM, whereas fragments would need to remove some nodes and insert other nodes in any container it's currently in.
Maybe notion of hyperfragments need to be extended to include that dynamics, gotta think about that.
I think instead of fragments you can just directly put children, it will work as expected.
I think instead of fragments you can just directly put children, it will work as expected.
Yes, children will work I know. Just an itch I had to solve. Anyway thanks for your library. I removed HTM dependency can you just check if my implementation is right? https://stackblitz.com/edit/vitejs-vite-voyet1?file=hy.js
I see. So you're saying that intuitively frag must be similar to div:
let foo = v('foo');
// these look similar
let frag = <>{foo}</>
let div = <div>{foo}</div>
// but when we insert it somewhere
container.append(frag)
container.append(div)
// and then update value to some other element
foo.value = <strong>FOO</strong>
// container must reflect that
container.innerHTML === `<strong>FOO</strong><div><strong>FOO</strong></div>`
// but factually `frag` just stringifies its content not re-inserting it.
// because fragment is headless/shallow/instanteneous and is disposed after insertionUnfortunately that's DOM limitation. If fragments were able to keep references to own children, it would be possible to update them the intuitive way.
That's possible-ish to "polyfill" I guess:
class HyperFragment extends DocumentFragment {
// not sure how to persistently keep ref to all children
}I see. So you're saying that intuitively
fragmust be similar todiv:let foo = v('foo'); // these look similar let frag = <>{foo}</> let div = <div>{foo}</div> // but when we insert it somewhere container.append(frag) container.append(div) // and then update value to some other element foo.value = <strong>FOO</strong> // container must reflect that container.innerHTML === `<strong>FOO</strong><div><strong>FOO</strong></div>` // but factually `frag` just stringifies its content not re-inserting it. // because fragment is headless/shallow/instanteneous and is disposed after insertionUnfortunately that's DOM limitation. If fragments were able to keep references to own children, it would be possible to update them the intuitive way.
That's possible-ish to "polyfill" I guess:
class HyperFragment extends DocumentFragment { // not sure how to persistently keep ref to all children }
Not sure if this is useful. https://gist.github.com/intrnl/0403cfad038728263ffdf8a1a95b671c
Looks interesting! It depends on TemplateFragment though - not sure what that is.
Curious how did you find it
Looks interesting! It depends on
TemplateFragmentthough - not sure what that is. Curious how did you find it
I was just searching for reactive dom libraries I found https://github.com/Technical-Source/bruh in that there was liveFragment implementation from there I searched in google.
oops, actually my initial plan was to return async components. https://stackblitz.com/edit/vitejs-vite-qypzhx?file=main.jsx Now I am confused why this is not working as of now let's forget fragment.
See this: https://github.com/WebReflection/uwire
Ok. DOM Fragments seem to be very confusing and error-prone to extend.
Some bugs are very hard to trace and fix, like when fragment becomes a child of another fragment etc.
There's some alternative to document-persistent-fragment https://gist.github.com/dy/ac2c4f1f92b69ce1e593ff6dfec4e89c, but for this project I've decided to avoid live fragments, at least until there's some reliable DOM alternative.
Just use shallow nodes for observing children.
Thanks for the feedback though.
Hi, @dy Thanks for your effort and response. I have implemented a logic can you check and give your feedback so I can make this a library under 1kb?
https://stackblitz.com/edit/vitejs-vite-silhsl?file=src%2Fmain.tsx,src%2Fh.ts
is that possible for you can help me resolve a few issues above?
Honestly @kethan it looks like a hard and faulty way to do things. I would generally avoid fragments, live fragments etc.
Believe me it will be pain to look at that code after 1 month away.
That stuff
<>
<>
<>1</>
<div>u</div>
<>2</>
</>
</>
has really little if no value, but creates big maintenance burden.
From DOM perspective it's meaningless since document fragments can't be children of other document fragments, maintaining reactivity. That's meaningful only in case of VDOM.
Besides, such libraries aren't created in gists/playgrounds - they need exhaustive tests, benchmarks, repository etc etc.
I would just build your app with DOM nodes.
If you can show what layout you're expecting I can show how can that be done with DOM nodes.
Honestly @kethan it looks like a hard and faulty way to do things. I would generally avoid fragments, live fragments etc. Believe me it will be pain to look at that code after 1 month away. That stuff
<> <> <>1</> <div>u</div> <>2</> </> </>has really little if no value, but creates big maintenance burden. From DOM perspective it's meaningless since document fragments can't be children of other document fragments, maintaining reactivity. That's meaningful only in case of VDOM. Besides, such libraries aren't created in gists/playgrounds - they need exhaustive tests, benchmarks, repository etc etc.
I would just build your app with DOM nodes. If you can show what layout you're expecting I can show how can that be done with DOM nodes.
Hi @dy How are you? Yes, you are right fragments are a pain. I was about to quit but suddenly something struck and I made this library https://github.com/kethan/uele. This solved most of the issues. You are sube and hyperf was such an inspiration. I really loved it.
Kindly check the library and this playground to play around. Any feedback from you is valuable. https://codesandbox.io/s/uele-test-kpkyrz?file=/src/index.jsx
I want to add more generic subscribers to sube like solid.js state/preact signals/ etc. I want some ideas. So we can integrate popular state management in JSX (hyperf concept is wow).
Thanks.
Hey. Sure, I think extending sube with other common observables would be nice.
hyperf/value-ref/spect survived so many iterations you should know, like, years. Current version is fast practical consensus.
I'd like somehow aligning it's functionality with bruh, it seems they both have very similar API if not identical.
As for uele - it's missing a bit elaborate docs, at least to understand main feature and main value/difference from bruh or hyperf.
One thing I noticed you use for o - o() used as get, and o(value) used as set. That syntax is directly observable, but I practically found that syntax a bit noisy and often confusing, compared to reading/setting o.value, o.value = 123.
@dy Yes, I have an idea for extending. Let me share my thoughts with you later.
Yeah, I am aware you have put in lots of effort and I have thanked you in my git repo readme. Thanks once again.
I have updated some docs and examples at: https://github.com/kethan/uele and https://github.com/kethan/ulive
Hmmm, it's all preference. I prefer the obs value and it doesn't confuse me. Anyway, I have made it in such a way users can write both Obs or Value ref. Check the below example.
https://stackblitz.com/edit/vitejs-vite-5h1z4i?file=src%2Fmain.tsx
From here I am planning to make it custom subscribable to use any state managers.
Looks nice. Personally I'd prefer name 'fx' over 'effect'. Also reduce some undecisiveness about signal/obs, since these are identical APIs and only make noise, kind of putting responsibility from dev head to user head to decide api flavor.
Also - are you saying that fragments that uele creates are capable of live updates being inserted into other fragments or other elements? It seems like tests are needed for framework, it seems fragile without.
Yes. I am thinking of something like this. But not sure how.
let thing = (fn) => {
return {
subscribe() {
}
}
};<div>{thing("Hi")}</div>
This subscribe function object will be called dynamically in other frameworks or state managers to update the UI node.
The test cases I need to learn how to write a one. ;)
Hi @dy how are you?
I have finally updated uele https://github.com/kethan/uele to allow any reactive library. Can you have a look and give feedback?. Thinking how to port value-ref ๐ค
And next is to add swapdom for array.
Hi @kethan. I was recently building a project with preact/signals (instead of value-ref) and it almost perfectly solves the issue of model layer.
There's just a bit of friction with preact - generally I'm not fan of non-html jsx stuff like components: better have interchangeable pieces of valid html in js.
Reopening: live fragments seem to be a nice little feature and it's not really unexpected - it's fine if elements keep updating themselves, providing user knows what he's doing by passing reactive values.
Nested fragments are not supported though, only top-level fragments with reactivity.