4 ms·
I've been playing around with your library for the last hour and so far it's excellent, pretty what I had hoped for after working with React for a while. The pe
by saiojd 6y ago
I've been playing around with your library for the last hour and so far it's excellent, pretty what I had hoped for after working with React for a while. The performance of individual renders is one area of improvement but I think the main contribution is the clarity the update model provides.
React works well until you try to avoid re-rendering and then it really falls appart. For example, updating a context re-renders the whole component chain from producer to consumer, and trying to block useless re-renders with shouldComponentUpdate easily leads to mistakes where children don't update when they should. Since React rendering use lazy evaluation of JSX expressions, tracking who exactly updates and when is much harder than what it might seem initially (akin to tracking mutations in a language with lazy evaluation). As this library actually tracks dependencies and only re-renders what you want, all of this bloat is avoided. One aspect that impresses me in particular is that JSX expressions actually return real DOM nodes, making it easy to keep references to them for imperative operations (not a big deal but so much nicer than React refs).
I'm wondering why you opted for the setState API rather than a nicer imperative API like Mobx. From what I can gather, state changes are tracked by diffing? Why not just return a proxy?
- atfzl 6y agostate changes are not tracked by diffing, it is much more interesting. You can read about it here https://www.atfzl.com/understanding-solid-reactivity-basics https://www.atfzl.com/understanding-solid-reactivity-basics
- saiojd 6y agoThanks, that makes a lot of sense (basically Mobx but fine-grained). When I mentioned diffing, I meant for updating state objects like lists. Your `<For/>` element only updates if a new list is created, but only re-renders the changed elements. I assume this is accomplished by diffing the old and the new list?
- ryansolid 6y agoYes you are correct. Use diffing here actually very similar to VDOM libraries. It was more performant(and consistent) than just propagating the change purely through manipulation of a proxy. Especially if you consider things like batching.
- saiojd 6y agoThanks. Batching was more efficient with diffing because you can avoid keeping track of which array indices changed within the same batch?
- ryansolid 6y agoYes and keeping the order of application. I actually played with this for a bit. Early Solid let you basically codify mutations you could send in as data. I thought it was interesting to do something like Redux where instead of producing the next state you produced the mutations that would be applied, and then applied them at a granular level instead of diffing. But when you add time into the picture you actually have keep track of more. I'm not saying it's impossible to tackle this just the people I know who have been working at this always hit limitations where they need to fall back to diffing anyway. I think it would take some doing to determine where the book keeping cost would be worth it. It is rarely as simple as more granular is better.
- ryansolid 6y agoI do return a proxy. It's just readonly. I really like the unidirectional data flow and explicit read write segregation of react. This adds so much control without having to add Framework like control mechanisms. I know it isn't easy, but it something that makes the solution elegant in the end. I think that passing data should also mean the choice of passing the ability to update it. That is a problem I have with almost all reactive implementations in libraries today. I think React has that part just right.
- saiojd 6y agoI'm not sure I understand your argument in favor of setState correctly. By splitting the state into two parts (a read-only view, and a setState function to update it), isn't the opposite being accomplished? It is now possible to pass the data without passing the ability to update it, or vice-versa. Which could very well be desirable but could be accomplished by other means (i.e. leaving to the parent the choice of passing a read-only or a mutable proxy). Settings aside the superficial issue of syntax, the main thing I dislike about the setState interface is for updating things like lists, where you need to perform a full copy just to insert one element. That being said I haven't yet looked into how exactly you handle lists.
- ryansolid 6y agoI mean it's basically the same thing as you do with React. You create lens functions more or less to handle get/set over the state object. Solid's setState has a lot more capability than React's handling nested updates with an ImmutableJS or Immer inspired API. The clever part here is immutable libraries already have API patterns to describe mutation so I just apply them here. So instead of spreading everything and cloning you keep the mutation locality for performance but keep the control of immutability. Also don't be worried about copying the array that much. I'm doing that in the JS Framework Benchmark and it's still about the fastest with 10k items. The real key is identifying where you don't need to update the list at all just the items in it. That being said you can do an update without copying the array like this: setState('list', state.list.length, newItem); Granularity of performance isn't a silver bullet. Being fine-grained doesn't necessarily make everything faster (especially creation). The power is that granularity is arbitrary so it can be maximized to the type of situation, completely independent of component structure.