What should go into JSX 2.0?
github.com
github.com
> Computed attribute names.
If you need this, you're probably being too clever. If there's a legitimate use for this, I've never seen it in the past 2 years I've been using JSX with React.
> Object short hand notation.
> Drop the need for curlies around attribute values if they're a single literal, or parenthesis.
Is it really that much more work?
> Implicit do expressions.
> Conditionals
> Loops
If you need control statements in your JSX, you're doing it wrong. When you need these things, this is a sign you need to break your code into smaller chunks. Move this logic into separate functions, lambdas or variables and interpolate them in. Now you've labeled your code and made it more composable. This is called self-documenting code and it's a lot easier for others and your future self to read.
All of these wouldn't be so bad if it wasn't a proposal to justify breaking changes. I really don't want to have to deal with two versions of JSX that are incompatible. That just sounds like hell.
The whole point of JSX is that it isnt a template language and is just a wrapper around objects with properties.
Oh, and you have to learn it as well, because someone had a fetish of avoiding python/php/perl/... in templates, inventing <loop start=1 end=15 step=1> to replace (1..15).each.
Nowadays we're replacing loops with recursion or map but fundamentally, there's no difference. If you have a collection and you want to render it, you need the logic of repetition in a template, and there's nothing wrong wit h putting it there.
10 years ago, you would often see html with interspersed business logic, even SQL. That just doesn't happen anymore. Now, fruitless attempts to further reduce logic in templates just lead to convoluted overengineering who at best try to hide the logic.
haha, harsh. I don't disagree but there are cases where they make sense (pure, designer focused, flows for example). But anywhere where a dev will be involved generally a template language is solving the wrong problem.
JSX is quite an elegant solution to the issue: provide abstraction, but allow underlying logic to be in the same language.
For loops I'll create a collection of items in a function (usually done with map against a prop collection) and drop that variable in my JSX.
Basically the same for conditionals. If I want a thing, a var gets a component assigned. Otherwise it's null.
Are these bad patterns, as is?
Unfortunately if control flow gets bolted onto JSX we can expect to see a lot less of this. Others will assume that this is the way business is done. That is, creating hundreds of lines of hard to follow conditionalized pseudo XML. I realize this already occurs in more bastardized forms, but it shouldn't be encouraged by new language features.
I'm good with how it is right now. The sour stuff is in the js, and the sugar in the jsx.
My personal taste though often does wish for object shorthand and dropping curlies. My sense off the top of my head is that the majority of my actual props look something like `<Widget user={user} id={id} timestamp={timestamp} />` since I mostly avoid setting up data inside JSX. Is it a big deal? Of course not. But it would be nicer to just write `<Widget user id timestamp />` or `<Widget $user $id $timestamp />` or whatever syntactic sorcery would be settled on.
A modest advantage of dropping curlies is it reduces the already tiny force of one argument for styling in CSS over JS: "prettier and less typing". I certainly don't think they should be dropped just for this reason of course, but could be a side effect worth noting.
* https://www.npmjs.com/package/hyperx * https://www.npmjs.com/package/yo-yo
<ConditionalSpinner renderIf={data}><PersonRenderer person={data.person} /></ConditionalSpinner>
Problem is that the inner component will still be parsed and fail with cannot read property person of undefined. Yes, you can do this with a simple condition in your render function, but then it's not declarative any more.
<ConditionalSpinner renderIf={data}><PersonRenderer person={data.person} /></ConditionalSpinner>
Could be written better as: <PersonRenderer person={data.person} />
Where PersonRenderer would be defined as such: class PersonRenderer extends Component {
render() {
if(this.props.person) {
return <div>personcontent</div>
}
return <LoadingIndicator/>
}
}
Given this, I'm still not sure how an If "component" would be achieved (and further, you'd need an Else or a Switch component anyway if going down this route). Maybe you could explain the benefits of such a path? function withLoadingIndicator(Wrapped) {
return function(props) {
if (props.loading) {
return (<LoadingIndicator />);
}
return (<Wrapped {...props} />);
}
}
// ...
export class PersonRenderer extends Component {
render() {
return <div>personcontent</div>
}
}
export default withLoadingIndicator(PersonRenderer);It's often divided in two: One container fetching the data, and a pure component rendering it.
The "states" aren't related to container/dumb components or data-fetching/selection logic. They're purely about rendering the state for a given segment of the page. Perhaps this article[0] might help convey my intent. It's more about how to render "we didn't get data from that one endpoint for this section of the page" or "we're waiting for the data to show up", etc.
[0]: https://medium.com/swlh/the-nine-states-of-design-5bfe9b3d6d...
I usually use tests at the top of the render function to make sure that data is there, and return cleanly if it isn't. It just makes development easier as React components tend to get re-used. Within the data.person, in your example, the caller should make sure that it is complete, or pass nothing at all.
In the case you show I would either return <Spinner/> or the content, but never nest them. Have a conditional and two return statements, or one return statement with a ternary operator.
People might argue that this isn't the React way of doing things, but it's easier than setting a conditional classname to display none. It's also easier than breaking out a small amount of html into a separate component just because you want some conditional display logic.
function ConditionalSpinner({renderIf, children}) {
if (!renderIf) return null;
return children[0];
} <div *if={cond1 && cond2}>
<div>foo</div>
</div>
// results to
if (cond1 && cond2) {
return React.createElement('div', null,
React.createElement('div', null, 'foo')
);
}
I'm not sure why this is bad? Because it's looking like Angular?!! {cond1 && cond2
? <div>foo</div>
: null
} {(() => {
if (cond1 && cond2)
return <div>foo</div>
else
...
})()}
Though it makes GitHub think it's a Clojure file. {(() => {
})()}
Honestly I can't decide if I think this is ugly or beautiful. It's like the buffalo buffalo of JS. {do {
if (cond1 && cond2)
<div>foo</div>
else
...
}}
If JSX decides to implement "implicit" "do expressions", I suppose it would just look like this: {
if (cond1 && cond2)
<div>foo</div>
else
...
}
http://wiki.ecmascript.org/doku.php?id=strawman:do_expressio...note: i've changed your example to show code inside html tags, i'm aware it does something different to yours.
conditionals
<div>
@if(cond1 && cond2) {
<div>foo</div>
}
</div>
loops <div>
@for(var i in collection) {
<div></div>
}
</div>
variables <div>
@variable
</div>
ternary/longer statement <div>
@(variable ? 1 : 2)
</div>Maybe just a personal thing.
translates to
React.createElement('div', {if: <expression>})
This is bad because createElement always gets execute, whether the if expression evaluated to true or false. Changing this semantic would be messy.
import { h1, div, span, text } from 'html';
const user = { name: 'Dave', age: '30' };
return div('container',
h1(text('User info')),
div(span('field',text('Name')),text(user.name)),
div(span('field',text('Age')),text(user.age)),
);
I don't understand why there's so much activity in creating new languages/language extensions that duplicate functionality that can already be expressed as is, with just a bit of basic library support.CSS preprocessors are another example. Want to add loops, conditionals, and user defined functions to your CSS superset? Why not just use JS/TS instead, which has all the control features and can output CSS text just as well as Less/Sass/SCSS/flavour of the month.
view: function(ctrl) {
return m("div", [
ctrl.pages().map(function(page) {
return m("a", {href: page.url}, page.title);
}),
m("button", {onclick: ctrl.rotate}, "Rotate links")
]);
}
http://mithril.js.org/const animal = "cat"; <Component {animal} /> equivalent to: <Component animal={animal} />
Using spread ( `{...{animal}}` ) is already working and it will stop working with the new syntax.
On top of that killing two brackets and three dots will not give you huge performance / code-productivity benefit.
<Component {...{animal}} />
const componentProps = {}; <Component {...componentProps} />
https://github.com/yannickcr/eslint-plugin-react/blob/master...
That's a good stop-gap, but the tool itself should either pass through everything to the HTML or throw errors on anything that isn't going to get passed through. The silent failure mode is a UX bug.
a = {b:'c'}
a?.c //undefined
a.b //'c'
b?.c //undefined
I would like to see a successor that is more like HTML5 without the X. No idea how that could be realized though... ;)
1) JSX creates virtual DOM objects, not HTML tags. In places where the DOM and HTML use different names for the same thing, JSX uses the DOM's name. In particular, the "class" attribute is called "className" and the "style" attribute takes an object like { color: "white" } instead of a string like "color: white" (and the keys are like "backgroundImage" rather than "background-image"). The latter rarely comes up, but the former bites me all the time when incorporating markup from designers.
2) JSX requires all tags to be closed, like XHTML and all XML dialects. HTML 5 declares some tags to be self-closing, like IMG.
3) JSX removes whitespace padding inside elements. This usually results in the same visual result, except for those cases where HTML actually cares about extra whitespace (like in PRE and TEXTAREA).
4) Regarding TEXTAREA, you're encouraged not to use the inner content of the tag to define its default value. Instead, you treat it like an INPUT. (I think this is if anything an improvement.)
5) INPUT tags have some special behavior related to default values, but that's really more about React than JSX per se.
Overall I have found JSX pretty easy to get into. I appreciate that it really is just a very thin layer over underlying JS. I'm not totally sold on this approach versus the many, many, many other HTML templating systems out there, but at least it's easy to understand.