3 ms·
This is a thought-provoking new framework, thank you! It's novel and easy to understand. Having worked on sophisticated React apps, I've come to understand th
by dgreensp 9y ago
This is a thought-provoking new framework, thank you! It's novel and easy to understand.
Having worked on sophisticated React apps, I've come to understand the benefits and shortcomings of its architecture.
One insight is that properly encapsulating UI components and their behaviors leads directly and naturally to nested state machines. React is cleanest if you have one state machine, or N independent global state machines, that drive your app. Once you start trying to compose state machines to make a sophisticated UI, you end up in setState/callback hell, and then you try the Redux/Elm model, in which states are composed to make bigger states. I think it's fruitful to experiment with ways of composing state machines in which you don't just glue the states together, but you let the machines interact. Of course you still want to keep your program easy to reason about and avoid spaghetti, but I'm sure there are interesting patterns lurking there.
Another issue is components in React aren't supposed to address each other. You can easily call methods on your children using refs, though this is discouraged and interacts badly with the update cycle and higher-order components. Components not talking directly to each other is a great feature right up until it's not, such as when you have to deal with focus and selection changes. You're forced to contemplate taking what you thought of as pure UI state -- local to a component and tied to that component's lifecycle -- and moving it outside of React into a store whose structure parallels the component tree (which in turn parallels the DOM), just so that you can traverse it in a reasonable fashion and update it synchronously while DOM updates remain asynchronous. In Cell.js, these three trees become one.
- gliechtenstein 9y agoThank you, I think you pretty much nailed it! This architecture may not be very obvious to many people at this point but I believe it can enable a lot of interesting use cases (as well as being able to deal with even traditional app structures in more efficient and cleaner ways) One example is my own use case, where I'm working on a web version of Jasonette https://www.jasonette.com https://www.jasonette.com I couldn't find any existing framework that can achieve what I was trying to without becoming very complex. Thank you for the encouragement, you made my day :D
- dgreensp 9y agoSure thing. :) One thing I'm not completely clear on is the reactivity model. It seems like setting $components (for example) triggers a setter that updates the DOM? What about other DOM properties? What about underscore properties? Is there a dependency graph under the hood, and can you set up a property to depend on a calculation based on another property? Or is all data propagation explicit/imperative/"push"?
- gliechtenstein 9y agoYup, it works for all $ variables. As for the "_" variables they are meant to have no side effect on the DOM directly and instead only trigger a function called $update() automatically, which is where you can deal with all the view stuff. So the only thing you need to remember is to: 1. Declare whaterver "_" or "$" attribute you want to monitor initially on the genotype. 2. Once you have done that, every time you make a change to the underscore or $ variables, they automatically get queued up (via Nucleus) and trigger the $update() function right before the next render frame so they can be drawn all at once in a single frame. There are different ways of doing this, you could directly touch the DOM attributes (without any prefix) or the $ variables and they will update the view from anywhere. But personally my pattern when using Cell to write apps is to NOT directly touch the $ variables everywhere because it can be confusing, but instead keep the underscore variables as sort of a "model", and only touch those. And because updating a _ variable triggers an $update(), I can deal with all the view related stuff (changing the DOM attributes and $ attributes) in one place, inside $update(), which is the "reactive" feature. (But it's really up to you how you do it) You can learn more here https://github.com/intercellular/tutorial#2-update https://github.com/intercellular/tutorial#2-update Hope this helps! p.s. This document may be helpful in understanding the source https://github.com/intercellular/cell/blob/develop/GENESIS.md https://github.com/intercellular/cell/blob/develop/GENESIS.m...
- dgreensp 9y agoGot it. I immediately had a bunch more questions, some of which I tried to answer by playing around with the demo. Is "this" the actual DOM element? (Yes.) Then how is "context inheritance" implemented? The section named "How Cell implements 'context inheritance' does not ever say how it's implemented ;) (Getters and setters are set up by the framework.) It feels like inheriting everything would be a little messy compared to specifying what goes in context. Does changing something in "context" trigger updates in nested components that read that context? Apparently, no. Does assigning to $components always give you brand-new components, or is there any sort of diff/patch as in React? Apparently, always new components and new DOM nodes, so don't recalculate your children; you should probably access them via the DOM API and call methods on them instead. So you don't get "props flowing down" as in React. How are assignments to underscored props coalesced, e.g. using what notion of equality? What should you call props that you don't want to cause an $update? Why is it ok to call methods on other cells from $update, causing further updates, when this is frowned on in React, partly because of timing issues? I sort of wonder if making state changes synchronous is a huge win and solves a lot of issues; a lot of people are wondering if React makes a big mistake there. At the same time, it seems like there would be situations where you update underscored properties on A and B, and A is actually an ancestor of B, so updating A would destroy B. Then you wonder if the framework is going to be smart about the update order, and smart about dealing with defunct components during the update cycle. Edit: That's not even a good example of a timing issue caused by cascading updates. Can't think of a good one off the top of my head. Also edit: I haven't read the code, but it looks really short.
- rco8786 9y agoI find it hilarious that Cell goes through such effort to tell you that it's not a framework, and then you refer to it as a framework immediately. It's definitely a framework though (note that this is not an inherently bad thing)