facebook / jsx

The JSX specification is a XML-like syntax extension to ECMAScript.
http://facebook.github.io/jsx/
1.96k stars 133 forks source link

Object literal syntax for attributes #37

Closed tinganho closed 8 years ago

tinganho commented 9 years ago

Since you already support:

var x = { a: 3, b: 'foo' };
var y = <MyClass { ...x } />;

And the current operation in JS for spread syntax are:

var attributes = { attr1: 1, attr2: 2, ... } => {...attributes}

Notice the placeholder punctuations { } remains the same.

I just have to ask why you don't support:

var y = <MyClass { attr1: 1, attr2: 2 } />;

It's less foreign syntax for JS. Also the placeholder punctuations remains the same. It is also a more productive syntax then having to write multiple { } for each attribute.

RReverser commented 9 years ago

What's sense of having such syntax in JSX? It loses all the similarity with HTML and is not far from manually writing either

<MyClass {...{ attr1: 1, attr2: 2 }} />

or even

React.createElement(MyClass, { attr1: 1, attr2: 2 })

which is already possible anyway.

tinganho commented 9 years ago

What's sense of having such syntax in JSX? It loses all the similarity with HTML.

Familiarity with JS — since JSX is an extension of it. Don't need to introduce a new syntax for attributes/properties since it already exists one.

and is not far from manually writing React.createElement(MyClass, { attr1: 1, attr2: 2 }) which is already possible anyway.

<MyClass/> is still sugar for React.createElement(MyClass,....).

Also consider this:

onClick={this.handleChange} 

This is going from XML-context to JS-context. Personally I think the equal token = in XML conflicts syntactically with JS's colon token :.

tinganho commented 9 years ago

The current JSX syntax is for me like we need to write a different attribute/property syntax depending on context. Imagine this for the JS's array literal syntax:

In JS we have something like this right now:

var arr = [{attr1: 1, attr2: 2}, {attr1: 1, attr2: 2}];

We don't need to alter the syntax just because we are inside an array literal like the example below:

var arr = [<attr1: 1, attr2: 2>, <attr1: 1, attr2: 2>]; // an arbitrary syntax for object literal
RReverser commented 9 years ago

Don't need to introduce a new syntax for attributes/properties since it already exists one.

With such approach JSX wouldn't even appear since initially <MyClass x="a" y="b" /> was being transpiled to MyClass({ x: "a", y: "b" }) (and you still can use it for React.DOM.* even now).

Having own, non-JS, HTML-like syntax is exactly what 1) makes it easier for designers to play with React components even when they don't know enough JS (this already helps in a lot of projects) and 2) ability to change transpilation targets with time - for example, it can be easily changed to creating immutable data structures in ES7 without forcing user to change even a line in his code.

RReverser commented 9 years ago

Attributes are not necessarily object literals - it's just what happens to be current transpilation target.

Same as tags happened to be transpiled to pure function calls earlier and changed to factory calls for optimization purposes now.

tinganho commented 9 years ago

MyClass({ x: "a", y: "b" })

Call expressions syntax is not so suitable for hierarchy definitions. That's where XML shines.

tinganho commented 9 years ago

I thought the whole point with JSX was so that JS could have an element literal baked into the language?

let arr = [];
let obj = {};
let el = <>;
RReverser commented 9 years ago

let el = <>;

Well, definitely not this way, otherwise it would be the same as object literal and not XML element :)

tinganho commented 9 years ago

@RReverser would you not consider it as an empty element literal?

RReverser commented 9 years ago

Um, what is "empty element"? Definitely not - it should at least contain tag name, otherwise it doesn't make any sense.

syranide commented 9 years ago

What's sense of having such syntax in JSX? It loses all the similarity with HTML and is not far from manually writing either...

I personally don't care much for the HTML-look, I'd happily take JS-objects instead (easier to refactor), but I found the closing tag to be hugely important to readability and that's personally the biggest benefit I see with using JSX.

RReverser commented 9 years ago

@syranide I know, we two had these discussions over and over. And hi again :)

tinganho commented 9 years ago

Just thinking out load now. And skip thinking in React or HTML terms and more in general (hierarchy) terms.

Current literals are:

Array literal => for list and matrix data types.
Object literal => for object data types.

Though non of the syntax suits hierarchy relations. Except for XML-like syntax. (Object literals lacks syntax for meta data)

Hierarchy literal => for hierarchy data types.

Each element consist of following object properties:

{
  constructor:  null,
  parameters: [],
  parent: null,
  children: null
}

The syntax <ConstructorName { parameter: value1, ...}></ConstrcutorName> are just sugar for defining an element object.

Let say that we use this new syntax for defining a family tree:

let familyTree = <GreatGreatGrandFather>
  <GreatGrandFather>
      <GrandFather>
       <Father><You></You</Father>
      </GrandFather>
  </GreatGrandFather>
</GreatGreatGrandFather>

Also note that there aren't any placeholder punctuations. In array literal there are [...] and in object literals there are {...}. Maybe we can define placeholder punctuations <...> for hiearchy literals, though auto inserted like semicolons?

So when we do:

var hierarchy = <Element>

it is treated as:

var hierarchy = <<Element>>

And if only specified as <> means empty hierarchy. And why is an empty hierarchy useful? For lists we can check if empty with .length. For object or map we can check its keys with Object.keys(obj).length. For empty hierarchy we can have a designated property for it too maybe .length?.

Then we don't need to null check and just do:

if(familyTree.length) {
}
ghost commented 9 years ago

+1 for this, mainly for conciseness. It does seem kind of odd to me that the spread operator is used for props but without the ability to concisely overload the spread within the same brackets, as you can do everywhere else with the spread operator.

I don't think it would hurt anything to support this ability. If anything it would make things simpler and more predictable (and more consistent) in many cases. The ability to use XML-like attributes would of course still remain, and so it would still be attractive to designers and people not entirely familiar with JS.

See https://github.com/babel/babel/issues/2209.

sebmarkbage commented 8 years ago

Note that this JSX specification is not coupled to React or even VDOM semantics of using property names as the output. It is equally valid to generate attributes in terms of a Map like structure or JSON-ML like arrays.

This example:

<div foo={bar} {...baz} />

Can be treated as any of these forms:

('div', { foo: bar, ...baz })
('div', [ ['foo', bar], ...baz ])
('div', [ 'foo', bar, ...baz ])
('div', CustomValueType({ foo: bar, ...baz }))

I also don't see how this is providing any new capabilities, other than maybe specifying inline getters and maybe decorators. However, if we go down the value type route, those may not be capabilities of value types anyway.

I don't think we're ready to commit to object literals being the only interpretation of attributes just yet.

So I'm going to close this out until we are ready at a point where more semantics can be specified.

NekR commented 8 years ago

@sebmarkbage if JSX already uses Spread operator for objects, when it's not matter to what it compiles, because it already uses plain JS objects for properties, so this point is not relevant. Also

<div class="" { ...myProps } { ...{ class: 'override', something: 'else' } } />

should be already equivalent to:

<div class="" { ...myProps, class: 'override', something: 'else' } />

So practically, what is requested here is just a sugar around such structure. And if you just do not want add such sugar to the spec, then this makes sense. Otherwise this all seems strange since it shouldn't be the problem to support such syntax.