Closed mrjjwright closed 5 years ago
I think this also jives with what @ryansolid says here https://github.com/adamhaile/S/issues/21#issuecomment-471271882
Short answer is yes.
It is common for these types of libraries to special methods/types for arrays. One of the biggest gripes pre MobX 5 (which switched to proxies) was that ObservableArrays weren't actual arrays.
That being said is if you deconstruct it a bit it makes sense why there are special helpers. Unlike VDom which makes faux virtual nodes a library like this makes actual nodes. So if you write list().map in an expression it has no choice but to do all the work since accessing list means any change to it will cause the whole thing to refire. Whereas VDom nodes describe the intended state pretty cheaply, Surplus would have to create the DOM nodes and nested computations. This is not cheap.
The next idea to cache values still has this problem since you'd want to hoist those outside of the computation but accessing list() will still cause the whole thing to reevaluate. The expression computation itself can't be smart enough to handle this as it won't know its content until it runs.
At minimum you need to use some sort of helper to make sure list isn't accessed directly in the expression computation and instead creates a nested computation so we can keep the cached values around. So either you extend the signal prototype with a list.map(notice we don't access the value with ()) or write one that takes the list signal as an argument like, map(list, item => ....). So at minimum you need a signal aware helper, meaning a generic map method found elsewhere will not do.
At that point understanding what happens in that helper is related to the other conversation since as soon as are hoisting cached mapped values you have to be aware of the computation lifetime.
Wow intriguing answer as to what goes into that decision, thanks!.
I guess looking back on your answer, the question that comes to mind, is how does Surplus do it then without such a helper? This sounds like an explanation of how your lib does it, but curious how Surplus gets away without it.
Oh I get it, "extending the Signal prototype" is is what SArray essentially does.
I have yet another question about fundamentals that my slow brain is not quite getting. I come from the React virtual dom world where I always put a key on every item in a dynamic list so that React's virtual dom implementation can safely do a keyed list reconciliation. I notice no use of keys here in Surplus. So in a list situation on the first render, Surplus is going to emit a set of real DOM nodes, and on subsequent renders it will do the same and reconcile them. I see from the source that reconciliation is done by being
equable
. 2 nodes are the same if they are strictly===
or if they are string or Text nodes that can be reused. Now I also notice that in most of the examples that typically SArray maps are being used, which I believe memoize computations in items in the underlying array that haven't changed. Is that the trick to doing the reconciliation without keys since the SArray map will produce a node list that is a blend of old and new nodes? Should Surplus then only be used with SArray?