Comments (33)
Another way to support at least CoffeeScript could be to make the component constructor a little more lenient. I've been playing a little with this, and my favorite syntax so far is something like this:
L = React.DOM
HelloComponent = React.createClass
render: ->
L.div class: 'myClass',
L.p 'Hi there, ', @props.name
L.input type: 'button', onClick: @onClick,
value: 'Click me'
That is:
- Allow props to be omitted.
- Allow more than one child.
And, since CoffeeScript is a bit weird, combine multiple "props" objects into one. (CoffeeScript turns that last line into:
L.input({
type: 'button',
onClick: this.onClick
}, {
value: 'Click me'
});
).
It may not be HTML, but it is quite readable IMHO.
from react.
@edc what do you think of this?
var HelloMessage = React.createClass({
render: function() {
return React.DOM.div(null, 'Hello ' + this.props.name);
}
});
This works out of the box (and is what JSX actually compiles down to).
I fear a solution that parses strings because of performance implications, having to include a parser in the core (which is more bytes down the wire) and that it becomes easier to introduce XSS vulnerabilities.
from react.
Well, that's not really better, it's just writing the JSX transform yourself. Which sucks (otherwise we wouldn't have JSX at all). And if we ever decide to change the output of the transform things are going to fail weirdly.
What @edc is proposing is nice in that since it's just JS, things like coffeescript can parse it and not choke.
What we could maybe do is have the JSX transform step look for this _dom_
method and parse the contents, turning it into Reacty code. The only additional bytes are then in the transformer, which isn't bad.
from react.
I like @zpao's proposal. The _dom_
could simply be a syntactical "escape", and the JSX transform can treat the argument of _dom_
as a string literal instead of an expression and therefore bypass the performance implications and XSS issues. The JSX transform can simply abort if the argument of _dom_
is not a string literal.
from react.
Ah, now I get what you meant by gettext
-style. That sounds like a pretty good idea to me.
from react.
@holmsand you may want to check out what coffeekup does: coffeekup.org
You can pass arrays as children today. We try to avoid them for single-child nodes so we can save an array allocation. I bet we could build a jsx-coffee package that wraps up all the ReactNativeComponents in React.DOM to expose this interface pretty easily. What do you think about that approach?
from react.
@petehunt I'm not that fond of coffeekup (eval evilness, and whatnot).
About arrays of children: I just found it confusing a couple of times that multiple children just disappeared without any warning... And the CoffeeScript gets a little bit prettier without the []s.
Anyway, wrapping is exactly what I did when playing with React. I ended up with something like the code below (with some auto-autoBinding thrown in). But it sure would be nice to have a common, human-usable API for us preprocessor-challenged users...
Reactor = @Reactor or= {}
isProps = (val) ->
typeof val is 'object' and not
(React.isValidComponent(val) or Array.isArray(val))
copyObject = (from, to) ->
for own key, val of from
to[key] = val
to
wrapComponent = (compFn) ->
(children...) ->
# Coffeescript breaks objects into more than one with this syntax:
# L.input type: 'button', onClick: @onClick,
# value: 'Click this button'
# So combine second object with first.
# Also allow props to be omitted, and class instead of className.
props = null
while isProps children[0]
props = copyObject children.shift(), props or {}
if props and 'class' of props
props.className = props['class']
delete props['class']
if children.length
children = children[0] if children.length is 1
compFn props, children
else
compFn props
Reactor.DOM = {}
for own key, val of React.DOM
Reactor.DOM[key] = wrapComponent val
Reactor.createClass = (comp) ->
newc = {}
# autoBind all handlers starting with 'on' or 'handle'
for own key, val of comp
if key.match /^(on|handle)/
val = React.autoBind val
newc[key] = val
wrapComponent React.createClass newc
from react.
One of the common use case of JSX is to embed complex Javascript code within the XML like
<ul>
{this.props.children.map(function(child) {
return <li>{child}</li>;
})}
</ul>
How would you write that in Coffeescript with your suggested method? Would the code inside of the {} be written in Javascript? Wouldn't that be weird to mix coffeescript and Javascript?
from react.
I still prefer JSX since it is HTML. To quote the React's own document:
- It's easier to visualize the structure of the DOM.
- Designers are more comfortable making changes.
- It's familiar for those who have used MXML or XAML.
IMHO, DSL based on CoffeeScript can easily become a mess because of the mixture of optional parenthesis/braces and significant whitespace. For instance, if you forget a trailing comma and instead of
L.input onClick: @onClick,
value: 1
you have
L.input onClick: @onClick
value: 1
it will continue to compile, but the semantic is totally different.
from react.
I think the following can be made to work:
<form onSubmit={this.handleSubmit.bind(this)}>
<input type="text" ref="textInput" />
<button>Add</button>
</form>
(form onSubmit: @handleSubmit,
(input type: 'Text', ref: 'textInput'),
(button 'Add')
)
I think the best course of action is to make a CoffeeScript dedicated wrapper that has a nicer syntax than the constructor we have now.
from react.
With {}
(form {onSubmit: @handleSubmit},
(input {type: 'Text', ref: 'textInput'}),
(button {}, 'Add')
)
With {} and []: {} means attributes, [] means children
(form {onSubmit: @handleSubmit}, [
(input {type: 'Text', ref: 'textInput'}),
(button ['Add'])
])
Where the general form is (name {attributes}, [children]). Only children is optinal
from react.
@vjeux It would be really nice to treat CoffeeScript as a first-class citizen and have CSX in addition to JSX 😃. We might even be able to get rid of react.createClass
and use class MyComponent extends react.BaseComponent
. Am I being too unreasonable? 😄
from react.
If you feel like making JSX work on CoffeeScript, that would be awesome :) I don't think that anyone is working on it right now.
About class extension, we could totally do that. We didn't do it because there's no class support on raw Javascript.
from react.
@vjeux cool. Will try to put something together. Off topic, but are you guys attending any meetup to get more traction?
from react.
@edc Of course it would be nice to have a preprocessor for CoffeeScript as well - as you say there are some downsides to using a DSL. But there are upsides as well, since the preprocessor is essentially creating an entirely new, and somewhat unfamiliar, language, with gotchas of its own.
from react.
@edc Yes! Nothing on the books yet but if you have suggestions on particular meetups let me know.
from react.
The CoffeeScript grammar appears to be fairly well-defined and extensible. So it might be even easier to write a transformer for XML literals in CoffeeScript than it was to implement JSX using Esprima.
from react.
I'm not sure if we can ever make it work but this is valid CoffeeScript :p
_<script>_
_ _<ul>_
_ _<div id="vjeux" /_>_
_ _<_/ul>_
_<_/script>_
If you ignore the _ this is also XML :p
from react.
The following could be made to work but doesn't really look like XML anymore and I prefer the version with () {} [] that I talked about earlier
R(
[ul a:"b", b:"c"]
@props.map (prop) ->
R(
[li]
R([span], prop, [_span])
[_li]
)
[_ul]
)
from react.
I just realized the following works fine:
HelloMessage = React.createClass
render: -> `<div>{'Hello ' + this.props.name}</div>`
So I guess you could close the issue. :)
from react.
I'd like to see this issue open. The above solution looks great but defeats the purpose of coffeescript by making a potentially big chunk of code javascript. Plus, it kills the syntax highlighting, which really makes a designer's life hard. And if I'm not mistaken, the whole point of jsx is to write HTML-like code in a js file isn't it?
(Disclaimer: I'm still checking out react and am by no mean fluent in it. Please point out any false assumption I'm making)
I have many thoughts on this matter. First, I happen to have written a 21 lines, fully functional templating engine in coffeescript not so long ago. It has mostly coffeekup's sweet, clean syntax but without the "eval evilness" @holmsand mentioned: https://gist.github.com/chenglou/5819861 (please also ignore the freakish mess code, it was more of a successful code challenge than anything else). Since all the tags are functions, I'd imagine it's pretty easy to convert them into the current React.DOM calls. Plus, it looks like a cleaner HTML one would actually want to write in. AND! Natural syntax highlighting, code checking and all in editors.
The downside of this is that just like many solutions proposed here, this looks clean at the expense of regular javascript. I have some neat solutions in mind but, another time.
Second, just like lots of the newcomers, I'm still a bit uncomfortable at the idea of writing my markup, especially markup that needs compiling, in my js files. It's mostly a mental barrier. I have an idea for the best of both worlds but now that I'm writing, I think I need a bit more reflection on this. I'll open a separate issue once I get more acquainted with this library.
from react.
So if you wanted, you can just use React.DOM
directly and forget about JSX. @vjeux has done that - check out http://blog.vjeux.com/2013/javascript/react-coffeescript.html
It's the integration of JSX into coffeescript that's hard. coffeescript probably chokes on <markup>
and our JSX transform works with a JS AST, so it can't parse coffeescript. In order of this to just work, support needs to be added at one end of this. We are not currently in a position where we can spend time adding coffeescript support to our transform. Maybe we could add support for a suggestion like _markup_
, but that would likely end up in a different esprima fork, and we would only be adding this to work around coffeescript.
As to your last point, I'll reiterate that you don't have to use JSX. You can write the React.DOM()
or MyComponent()
calls yourself. We use JSX and we think it makes life easier. We've started thinking about some solutions where you can write your render function separately from your component, so your markup could live separately but we haven't gone far down that path. I'm happy to hear your thoughts!
from react.
@chenglou how about something like this? http://jsfiddle.net/hdrV3/1/
Just a thin wrapper around React.DOM to make it more DSLy in CoffeeScript.
from react.
Yeah.
But to reply to @zpao, I do want to use JSX though, because it's the only thing that makes sense for designers. I was actually thinking about isolating the JSX (and maybe even css) in another file, this way people will be able to create react components that contain a js, a jsx and a css file. And instead of compiling JSX, you kind of insert it into the js file. Or maybe (as much as I appreciate what you guys are doing with JSX) dropping it completely and make it a mustache-like template. But like I said, I haven't experimented with react enough to provide concrete examples, so I'll comment once I get more familiar with it in a short while.
from react.
This conversation may interest you: https://groups.google.com/d/msg/reactjs/dpGem2Yr6do/8VuGYEAzqTcJ
from react.
@chenglou Just to add another datapoint:
It turns out that the idea of @edc works quite well in practice, at least for me (i.e. escaping JSX in Coffeescript, and then compiling the resulting .js file using React's compiler). I've just rewritten something like 1500 lines of code using that method, and so far it's been an absolute pleasure. I.e. using code like this
Dropdown = React.createClass
render: ->
@transferPropsTo `
<div class="btn-group">
<button tabIndex='-1' type='button' class="btn dropdown-toggle"
data-toggle="dropdown">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
{this.props.children}
</ul>
</div>`
I actually like the 'look' of JSX in Coffeescript better than in JS, since the escaping clearly demarks what is JSX and what is not.
from react.
Shameless but pretty relevant plug: some of the syntax ideas being discussed here are actually close to something I've been working on called reactive.coffee, an embedded DSL for building reactive UIs (in a scalable manner).
from react.
I just want to quickly add that if you're using GitHub's Atom, it (kind of) highlights syntax within backticks.
from react.
Ok, I don't think we are going to extend the transformer in ways that have been discussed, so I'm just going to close this out. People have found solutions that are working for them in different languages.
from react.
I just found https://github.com/jsdf/coffee-react-transform which appears to be a JSX transformer for CoffeeScript. I haven't tried it but it looks promising -- if anyone here tries it out, it would be great if you could report back with your results.
from react.
I just converted a small project to use CJSX. Worked perfectly as far as I can tell and looks very nice. See https://github.com/KyleAMathews/community-mapping-tools/blob/master/react_components/sorted_addresses.coffee or https://github.com/KyleAMathews/community-mapping-tools/blob/master/react_components/header.coffee
from react.
I'm working on CJSX quickstart. Has a Gulpfile to build coffeescript/sass as well as integration with Jest. WIP but coming along.
https://github.com/KyleAMathews/coffee-react-quickstart
from react.
from react.
Related Issues (20)
- Bug: Wrong detection of non-boolean attribute when working with React API HOT 2
- Cannot find name 'dialog' HOT 2
- Bug: useMemo has a problem of executing multiple times without changing dependencies HOT 2
- Bug: bug de teste
- [React 19] Export SuspenseException HOT 2
- [React 19] [bug] SVG with dangerouslySetInnerHTML content does not trigger first click HOT 8
- [React 19] - `ReactElement` created from `React.createElement` are not renderable anymore HOT 3
- [Compiler Bug]: function parameter inside component override outer parameter incorrectly
- forceUpdate not work in child component GuardGraph
- [React 19] useOptimistic is not updating its optimistic collection immediately HOT 6
- Bug: useEffect and Event Handler Timing Regressions in React 18 Legacy Mode HOT 1
- [DevTools Bug]: No way to debug suspense events
- [Compiler Bug]: setState in useEffect / react compiler and eslint hooks plugin HOT 1
- [DevTools Bug] Cannot add node "20468" because a node with that id is already in the Store. HOT 1
- [Help Wanted] How can I become a member of reactjs? HOT 1
- [React 19]useEffect cleaned the wrong state in StrictMode HOT 3
- Bug: Inability to prioritise hydration & react yields too willingly HOT 1
- [DevTools Bug]: Script tag connection method not working in 6.0.0 HOT 1
- Bug: DevTools 6.0.0 element inspector not working with React Native 0.75 HOT 1
- Bug: re-rendering order of onBlur and onClick inconsistent between desktop and mobile browsers
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react.