Coder Social home page Coder Social logo

Comments (33)

holmsand avatar holmsand commented on December 10, 2024 1

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.

petehunt avatar petehunt commented on December 10, 2024

@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.

zpao avatar zpao commented on December 10, 2024

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.

edc avatar edc commented on December 10, 2024

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.

petehunt avatar petehunt commented on December 10, 2024

Ah, now I get what you meant by gettext-style. That sounds like a pretty good idea to me.

from react.

petehunt avatar petehunt commented on December 10, 2024

@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.

holmsand avatar holmsand commented on December 10, 2024

@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.

vjeux avatar vjeux commented on December 10, 2024

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.

edc avatar edc commented on December 10, 2024

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.

vjeux avatar vjeux commented on December 10, 2024

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.

vjeux avatar vjeux commented on December 10, 2024

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.

edc avatar edc commented on December 10, 2024

@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.

vjeux avatar vjeux commented on December 10, 2024

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.

edc avatar edc commented on December 10, 2024

@vjeux cool. Will try to put something together. Off topic, but are you guys attending any meetup to get more traction?

from react.

holmsand avatar holmsand commented on December 10, 2024

@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.

zpao avatar zpao commented on December 10, 2024

@edc Yes! Nothing on the books yet but if you have suggestions on particular meetups let me know.

from react.

benjamn avatar benjamn commented on December 10, 2024

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.

vjeux avatar vjeux commented on December 10, 2024

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.

vjeux avatar vjeux commented on December 10, 2024

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.

edc avatar edc commented on December 10, 2024

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.

chenglou avatar chenglou commented on December 10, 2024

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.

zpao avatar zpao commented on December 10, 2024

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.

petehunt avatar petehunt commented on December 10, 2024

@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.

chenglou avatar chenglou commented on December 10, 2024

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.

petehunt avatar petehunt commented on December 10, 2024

This conversation may interest you: https://groups.google.com/d/msg/reactjs/dpGem2Yr6do/8VuGYEAzqTcJ

from react.

holmsand avatar holmsand commented on December 10, 2024

@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.

yang avatar yang commented on December 10, 2024

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.

damassi avatar damassi commented on December 10, 2024

I just want to quickly add that if you're using GitHub's Atom, it (kind of) highlights syntax within backticks.

from react.

zpao avatar zpao commented on December 10, 2024

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.

sophiebits avatar sophiebits commented on December 10, 2024

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.

KyleAMathews avatar KyleAMathews commented on December 10, 2024

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.

KyleAMathews avatar KyleAMathews commented on December 10, 2024

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.

anthonybrown avatar anthonybrown commented on December 10, 2024

👍 @KyleAMathews

from react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.