{div, ol, li} = React.DOM # global exports
div null,
ol null,
for result, index in @results
{a, span} = React.DOM # local exports
key = doSomeLookup( result, index )
href = otherLookup( key )
li {key}, [span(null, "Hello "), a({href}, "world")] div null,
RadComponent onClick: @handleClick, model: @props.thing
and so forth. <div>
<RadComponent onClick={this.handleClick} model={this.props.thing} />
</div>[0]: http://gulpjs.com
[1]: https://github.com/jjt/LUXTRUBUK/blob/master/gulpfile.js
[1]: http://brunch.io
({div, ol, li} = React.DOM) # global exports
(div null,
(ol null,
(for result, index in @results
({a, span} = React.DOM) # local exports
(key = (doSomeLookup result, index))
(href = (otherLookup key))
(li {key}, [span(null, "Hello "), a({href}, "world")])))
However, assignments and binary operators are still infix, and comas are needed.=^_^=
a friend at twilio pointed me to a library called JUP
it lets you express html as json. i don't understand why this isn't more popular.
[ "div", { class : "a-class" }, [ "span", "you can use all of your json tools to edit the DOM" ] ]
so awesome!
So, that means
<div class="a-class">
<span>you can use all of your json tools to edit the DOM</span>
</div>
, right?This syntax makes more sense to me:
[{"tagName":"div","class":"a-class","children":[{"tagName":"span","innerHTML":"you can use all of your json tools to edit the DOM"}]}]
edit: ahh, see your point. ']' doesn't say what it's ending.
i've never had that be an issue with proper use of whitespace and newslines, but i see your point.
But CoffeeScript doesn't feel this way to me, which makes me want to stay far away. Yet so many smart people are building cool things with it, which makes me wonder if I just need to suck it up and get familiar with this new syntax.
Coffeescript is has a much trickier syntax than javascript, and if you use it all the time, then the brevity and reduced line noise is a slight win, but you never lose the downsides of the complex syntax.
If you're wondering what's wrong with coffeescript, it basically boils down to the fact that the syntax is chock full of unexpected exceptions. I notice that I and everyone I know sometimes get's surprised by what a piece of syntax actually compiles to (not a good sign).
Some examples:
f
a: 1
b: 2
compiles to f({ a: 1, b: 2 });
but f
o
fails to compile (so whether you can break an argument onto the next line depends on whether it's an object literal)Comma's to delimit multi-line arguments are usually redundant, but not on the first line, so...
f 1,
2
3
compiles to f(1, 2, 3)
but f 1
2
3
doesn't compile at all.Curly braces aren't entirely optional, so
o = [ {
a: 1
b
} ]
compiles to o = [ { a: 1, b: b } ]
but o = [
a: 1
b
]
compiles to o = [ {a:1}, b]
Note that this is particularly tricky if you have functions with complexly nested arguments, which is what the original artical is proposing to use for React. In JS that would be messy but unsurprising, but in coffeescript you will run into the occasional miscompilation, especially since it's indent sensitive but very flexible with those indents.For example you may start out with:
a
href: uri
span
className: "x"
"content"
...then decide to remove the class, and end up with... a
href: uri
span
"content"
But the second example actually nests the content inside the <a>, not the <span> (and it'll crash at runtime since span is passed rather than called).You can even have code that compiles & runs and just returns the wrong value:
div
id: "foo"
span null
"content"
vs. div
id: "foo"
span null,
"content"
Both result in valid JS that would run and display a valid DOM using React, but that comma changes the generated DOM. No warnings, no errors.All in all, I'd stay away from coffeescript if I didn't already have a large codebase to maintain. There are a bunch of other, better, compile-to-JS alternatives to make JS syntax less onerous - so you can get coffeescript's advantages without the nasty pitfalls.
eS6 will have fat arrows, but comparing CS today to JS today, I find the -> and => constructs are more than just an abbreviation, they make it radically easier to write AND READ code that makes heavy use of functions.
YMMV, of course!
There are better ways to learn new languages but cs is familiar enough to js that once you start coding you'll see it comes more naturally than you think.
ClojureScript also has a nice react kind-of-thing (now named reagent), though all the parenthesis makes it more noisy.
Overall though, React seems to be shaping up as a great solution for building reactive templates that isn't tied into larger frameworks like the solutions within AngularJS or Ember.js.
[1]: https://github.com/swannodette/om
[2]: https://github.com/holmsand/reagent
Reagent is basically just a native interface to React.
Om sort of reimplements React on top of React with a few modifications to make it more ClojureScripty (e.g. taking advantage of persistent data structures for state).
Quiescent takes React and turns it into a simple rendering library, leaving out any concept of state management.
1. Since React's event handling is also virtual (just like its DOM), cross-browser inconsistencies are taken care of for you. Sure, you could always attach your native events after mounting a component, but unless you're using jQuery or something with very good cross-browser support, you're bound to trip over the same browser bugs we already solved (IE8+!).
2. The virtual event system is super performant. It does event delegation for free. Internally, it's implemented as one single event handler at the top; no need to worry about whether you should put a click event on the list items, or on the list itself anymore. Events are also pooled.
3. Since the system's virtual, it opens doors to custom event plugins, i.e.:
<div onTapHold={bla} />
In fact, React's mobile tap event is a custom plugin. Removes the 400ms delay. You get the point.As I mentioned in the footnote, for my purposes (an app where I am likely to be the only user) I don't care about IE8 support, so it's kind of a bummer that I have to ship support for it. (In my day job I use Google's Closure library which has the same problem -- lots of additional complexity to work around IE bugs. I appreciate that removing this support isn't as simple as just compiling it out, too.) Similarly for the 300ms delay: the delay is gone on current Chrome on mobile (when you're using width=device-width; I only know this because I used to work on Chrome), which is the mobile browser I use.
Another way of saying this is that React is a combination of the virtual DOM stuff and a bunch of other "useful webapp stuff" like making events work across browsers and installing event listeners on the root element etc. I appreciate for you and the React authors' purposes those are the same problem and difficult to disentangle, but all I wanted to use was the virtual DOM part. (I guess the analogue would be like thinking Rails's ActionDispatch library is neat but then discovering you had to use their code-generation scripts and ORM library as well. Sorry if that metaphor failed, I'm not so knowledgeable about Rails.)
Anyway, since I'm mostly just tinkering with React etc. the size thing doesn't matter so much, which is why I put the comment way down in a footnote. But the whole "you must swallow the whole thing at once" thing is also the reason I've never looked into Ember or whichever other comparable framework. Maybe at some point, as a continued learning exercise, I'll attempt to reimplement the subset of React that I actually use to better understand the design space you already know.
1. Need a way to manage events: All the applications are handling events in one way or another. So you've got to have a way to implement event handling in a React application.
2. Cannot use existing event libraries: Because React manages its own Virtual DOM and has a very declarative nature, it is not easy to use raw DOM imperative APIs in other to implement event handling. Therefore, you cannot just plug in any event handling library, you've got to have one that works on-top of the Virtual DOM abstraction.
3. Performance is a requirement: The way you code in React is by describing the way you want the DOM to look like at all time. If not implemented properly, the performance is extremely bad. The fact that we implement global event delegation is not just a bonus, for some of our apps adding/removing event listeners is actually the bottleneck.
4. Bonuses: Having compatibility for IE8 and custom event plugins is actually the cherry on-top of the cake. Since React has its own event management, supporting those is pretty trivial and isn't a big amount of code.
We worked very hard so that React core is extremely small and doesn't contain "other useful webapp stuff". We have a special addons section for that: http://facebook.github.io/react/docs/addons.html
Yes, some compatibility code exists, but it's mostly just part of the default config which you can change. Additionally we don't inject things like the tap plugin by default so you aren't getting those extra bytes.
You can see what I mean about React's modularity by looking at this file https://github.com/facebook/react/blob/master/src/browser/Re...
Coffeescript has its problems as well, though, and one of the glaring issues is cutesy syntactic corner cases. Some of these are ok, taken individually, when they make the code maybe slightly more terse -- or more clear. But in the aggregate, they can leave us with something that is baroque, off-putting to the uninitiated, and hard to maintain. That's pretty much what I see in code here.
Having the curly braces around an object literal be optional was a language mistake: it simply introduces ambiguity. It doesn't save many keystrokes, and it wastes the time of the people who may eventually have to read code like this
R.p null,
R.a href:'foo', 'bar'
R.a href:'foo2', rel:'nofollow', 'second link'
Quick, is rel:'nofollow' part of the same object as href:'foo2', or is is the second argument to R.a?More alarm bells went off when I learned that we are using this Coffeescript clunker I did not know about previously: "beyond the first argument, the trailing commas are optional when you have newlines".
Wat? _Just the first line_ needs a comma? Did Ruby teach us nothing, folks? Irregular, tricksy syntax like that is a caterpillar, waiting to turn into a beautiful butterfly of a bug when some stranger innocently barges in to make a change 6 months from now.
Even if the language offers features like that, don't use them.
Optional braces around object literals allow you to write lines like this:
rectangle x: 10, y: 15, width: 500, height: 500
... and having newlines separate elements in lists makes a ton of sense in a language where whitespace is significant: requires = [
"jquery"
"underscore"
"d3"
]
... and also helps with the famous trailing-comma-in-IE error and comma-first controversy.If you're writing something that's convoluted enough that the features aren't helping you ... don't use 'em.
- optional braces cause more ambiguity (manifesting as either strange parse error messages on the front side, or bugs on the back side) than is warranted by the need to write:
rectangle { x: 10, y: 15, width: 500, height: 500 }
- newlines separating elements of a list is good, but it's really confusing to me why the following program would/should work with no comma after the "a": foo = (a, b, c) -> console.log a, b, c
foo "b",
"a"
"r"
Plainly, it _does_ work, but to me it feels like using a hole in my sweater to scratch an itch on my elbow.http://yang.github.io/reactive-coffee/
... note that it's not related to Facebook's React — just shares the name, and some similarities in surface area.
https://github.com/paiq/blackcoffee
Both have huge strange drop in Q3 2013. Problem with trends data?
This is not a "rule" that I came upon - I figured out how crappy having your templates tied to your JS makes working with quickly on my own. It is an absolutely ugly pattern.
if you can reference functions directly as attributes of your views it actually makes perfect sense.
mixing your templates and your code sucks when you're working in 2 languages across 2 files and you have to glue everything together. as soon as you're writing them both to the same target it makes perfect sense. especially since react still uses the DOM event model behind the curtains.
If the jsx syntax is what is holding you back is actualy optional like the Reactjs documentation clarify , you can use browserify or requirejs to separate the React.DOM objects in a diffirent file from your logic too. Cheers :)
Glad to see people are wising up to the benefits of minimal coupling.
For too long, web development seemed to revel in being a pig squalor of software engineering: "move fast and break things/just use Rails!/coupling doesn't matter anymore!" It's probably the influx of new developers. I don't mind that the mistakes are made as much as the collateral damage that occurred to analysis and design phases.
[1] - https://github.com/davemo/react-battleplanner/blob/battlepla...
[2] - https://github.com/davemo/react-battleplanner/blob/battlepla...
React's event handlers also serve as a unit under which state updates are batched. In a normal DOM event state updates are performed synchronously. (It seems like rAF should allow batching by default, but this hasn't been enabled because of some edge-case related to unit testing that I don't quite understand.)
{div, h3, textarea} = React.DOM
(div {className: 'MarkdownEditor'}, [
(h3 {}, 'Input'),
(textarea {onKeyUp: @handleKeyUp, ref: 'textarea'},
@state.value
)
])
http://blog.vjeux.com/2013/javascript/react-coffeescript.htm...Shameless plug here because author's site doesn't have comments: maybe you could try Vue.js: it is <12k gzipped, support IE9 and above only, and even less opinionated.