Very nice article! (Up also on Reddit)
> We can easily create small components, which are easily composed because they are stateless and side-effect free, and through that achieve reusable code
Well said, we are on the same page.
Now for what concerns the implementation, since I'm facing the same process (design a framework revolving around React for didactic purposes) I'd like to know your opinion on these points / issues:
- components are defined with an alternative syntax that uses positional arguments and breaks jsx. Is it necessary? I can see it's very nice for simple, small components though.
- local state is discouraged but still accessible, you gain in adoption and pragmatism but lose the stateless and side-effect free thing
- "statics" means something like controllers? It's not clear to me
- cursors are cool, but the `props.cursor.get('name')` syntax worries me, mainly the use of strings. Besides, in your excellent model where the state is immutable, why I can't directly access the component data and I'm forced to use the cursor? I guess for the updating stuff, but in general it seems unlikely that a view had the knowledge to update directly the app state without a mediator (a controller passed as statics?)
Hi and thanks for good and valuable feedback!
> - components are defined with an alternative syntax that uses positional arguments and breaks jsx. Is it necessary? I can see it's very nice for simple, small components though.
First, Omniscient has been updated to version 2.0.0 (to support React 0.12.0), where the syntax has changed some - as there were some breaking changes with React. But, buth the old syntax and the new doesn't break any JSX as far as I know. We have multiple examples using JSX (like here: https://github.com/omniscientjs/omniscientjs.github.io/blob/master/examples/jsx-todo/index.js for older syntax, and here: https://gist.github.com/mikaelbr/d54ad8871c79d15049d3 for the new). All though I prefer to use the JS syntax and having smaller components that are "easier" (subjective) to use (invoke). With React 0.12.0 and Omniscient 2.0.0, there is some difference between JS usage and JSX usage, as you need a `.jsx` suffix when using it in JSX. This is due to Reacts latest Component/Element change.
> - local state is discouraged but still accessible, you gain in adoption and pragmatism but lose the stateless and side-effect free thing
I agree with the trade off here. But thinking, all we can (should?) do is to give the tools for doing it the "right way", and showing examples of how to do it. And sometime there might be a use case for a local component-only state.
> - "statics" means something like controllers? It's not clear to me
This concept might be poorly explained. Statics are simply values that can be passed (and changed) without affecting whether or not the component should update. For instance, this is a good way to pass events objects down to components. Events objects can change between render loops, but we don't want to re-render the component. Statics can also be scalar values that you simply want to pass down, without affecting the update cycle. Makes sense?
> - cursors are cool, but the `props.cursor.get('name')` syntax worries me, mainly the use of strings. Besides, in your excellent model where the state is immutable, why I can't directly access the component data and I'm forced to use the cursor? I guess for the updating stuff, but in general it seems unlikely that a view had the knowledge to update directly the app state without a mediator (a controller passed as statics?)
You are correct that this is to update the component. So a component can get a cursor to a value in a immutable structure, and this cursor can again create sub-cursors to pass to children component. You could also have done this with only passing a "freezed" object, but you wouldn't have a way of swapping a value in a sub-structure that you get passed in a component - and trigger a re-render of the entire structure. Cursors are simply pointers to a part of a larger immutable structure, and with the way cursors are used, you can swap out a sub-part of a larger structure without affecting the other parts - and thus you can have a really effective tree-render. You can still use a mediator to swap the state (either through statics or something similar to Flux's actions/simple APIs), and pass in cursors as what value to swap. I.e
var SomeSubComponent({
update: function () { someAPI(this.props.cursor); }
}, function () {
/* Some Component Implementation using this.update() */
});
The Cursor API is a part of Immutable.js, and one can easily use another cursor implementation. (See https://github.com/omniscientjs/omniscient#overriding-iscursor-and-isequalcursor)
I hope I answered your questions and didn't misunderstand any of it. Don't hesitate to ask more or post an issue if you feel anything looks funky. Thanks again for feedback!