5 ms·
A lot of context on this here https://github.com/reactjs/rfcs/pull/107 https://github.com/reactjs/rfcs/pull/107 There's a subtle aspect of this change that may
by lucideer 6y ago
A lot of context on this here https://github.com/reactjs/rfcs/pull/107 https://github.com/reactjs/rfcs/pull/107
There's a subtle aspect of this change that may not be immediately apparent. One that, imho, significantly regresses JSX as an independent syntax outside of React (i.e. makes it much more coupled to React than before):
JSX is an SGML/XML-inspired syntax, and SGML/XML are languages with 3 dimensions of element definition: names, attributes and children.
Internally, React elements are represented in 2 dimensions, with children managed as a "magic" attribute, with the reserved magic key "children" (this is for performance reasons I believe). Before now this has always been an implementation detail of React. JSX is flexible enough that other libraries could provide an element factory method with a fully featured 3-dimensional internal representation. This change removes that flexibility.
To clarify the change, currently JSX compiles to:
createElement(name, attributes, ...children);
the new transform is now:
_jsx(name, { ...attributes, children });
- yesimahuman 6y agoThis is definitely concerning given that JSX has made its way into other projects like Vue and Stencil. I'm having trouble following though, what exactly does this limit?
- lucideer 6y agoIt doesn't really place any hard limits other than reserving the `children` key on attributes as a spec feature rather than an implementation detail. A 3rd-party factory can still break the `children` attribute out into a separate entity in their internal implementation. All it does is make the interface to the transform messier, by surfacing internal performance-related implementation details of React. This is code smell and I'd call it a syntax regression, but it shouldn't cause any severe limitations on what you can achieve. Personally I'll still continue to use JSX transforms with my non-React code once this lands. It's a great syntax.
- sroussey 6y agoReally sounds like children should be a symbol.
- uhoh-itsmaciek 6y agoThe announcement claims the old syntax is not going away. Do you think this is still a regression, even if it's only a React-specific alternative?
- lucideer 6y agoI did see the line: > there are no plans to remove the support for it But I don't really see what would drive this change if there wasn't any intent to remove it at some point down the line. Regardless, the wording of the article describes the new syntax as an "upgrade" so it seems likely this will the canonical transform in future.
- jonas21 6y agoI don't think I understand your objection. Can't a library trivially convert between the two representations if it wants to in its implementation of _jsx? Having children as a property of the parent isn't an implementation detail of React -- it's just a mapping onto Javascript, where objects have properties, and there's no independent notion of children. The new transform makes things more like Javascript, which seems like a good thing.
- lucideer 6y agoEDIT: (since you updated your comment, some of my original reply no longer applies) Part of the elegance of JSX is that it maps conceptually to the 3 dimensions of it's intended output structure (usually HTML) rather than being restricted by direct mappings to the 2 dimensions represented in JS objects. --- original below --- Both transforms work "like javascript"; I'm not sure how the new one is any different in that regard. While I do think it's a little nicer to not have to import React, they could've done that without changing the factory signature. Furthermore, I think the value of not needing to import React is slightly overstated. If you're using React & JSX, you'll be importing React in your application at some point regardless (so importing in the JSX component file shouldn't add weight). If you're using JSX without React, you don't currently need to import react anyway (as transpilers provide configuration options for factory methods: e.g. via Babel's react-jsx plugin's `pragma` config key)
- afiori 6y agomore than not needing react it looks like the new transformation is react-agnostic, so that all libraries that consume JSX can use the same transformation and put all application specific functionality in the _jsx function
- tln 6y agoThere is a practical limit on how many arguments can be passed to a spread parameter. I tested at 125k in Chrome just now. That's probably a couple orders magnitude more than a typical web page, let alone one parent node, but maybe that's part of why the change was made?
- JMTQp8lwXL 6y agoThe new output has bundle size improvements (per the announcement) but each call to the pragma function now instantiates a new Object. I'm curious if there are performance implications in very large React applications.
- lucideer 6y agoI guess every application will be different, so maybe, but this comes along with a large push to improve the performance of React's factory functions so it would be difficult to measure objectively.
- swyx 6y agowhat specifically did you mean by factory functions? if you meant createFactory, fwiw that was legacy and is now deprecated https://reactjs.org/blog/2020/02/26/react-v16.13.0.html#deprecating-reactcreatefactory https://reactjs.org/blog/2020/02/26/react-v16.13.0.html#depr... but if you meant createElement... i'm not sure the goal is perf? then again there was a lot to cover in that RFC and i may have missed something
- lucideer 6y agoSorry, yeah by "factory function" I just mean a function that generates element definitions for the renderer. `createElement` or `_jsx` in this case. W.r.t. the goal being perf., I'm not intimately familiar enough with React's source to know the exact gains (or losses) but there's a fair bit of discussion around perf. in the RFC thread. e.g. https://github.com/reactjs/rfcs/pull/107#issuecomment-520887661 https://github.com/reactjs/rfcs/pull/107#issuecomment-520887... re: prop re-use and https://github.com/reactjs/rfcs/pull/107#issuecomment-466487481 https://github.com/reactjs/rfcs/pull/107#issuecomment-466487... re: bit flags. There's also a lot of discussion around whether these are compelling, so it might not improve perf. at all.
- yunohn 6y agoFrom the post, it appeared to me as if this change was made, specifically, to remove the dependency on (importing) React. Are you sure that this results in making JSX dependant on React, instead?
- swyx 6y agofwiw under old JSX you were always able to change the JSX pragma to any other library you wish, so i'd rate this no change in "degree of dependency on React" tbh.
- lucideer 6y agoFirstly, you're right that the main content of the post is re: not needing to import React. My comment was just pointing out that they have additionally changed the factory signature (an unrelated change). Secondly, I should point out that JSX is currently not dependent on React. You can use JSX now without React, either via Typescript (built-in support) or via the custom `pragma` config key in babel's JSX plugin. The change described in the article makes it unnecessary to import the full React lib into each component file when using JSX with React. I'm not sure what the benefit of this is tbh...
- henryfjordan 6y agoYou'll be able to tell babel to use a different "importSource" instead of `React`: https://babeljs.io/docs/en/babel-plugin-transform-react-jsx#importsource https://babeljs.io/docs/en/babel-plugin-transform-react-jsx#...
- lucideer 6y ago`importSource` is just a newer version of `pragma` (I mentioned above, listed on that page below `importSource`), and works fine right now without this new transform.
- henryfjordan 6y agoI was responding to this statement: > The change described in the article makes it unnecessary to import the full React lib into each component file _when using JSX with React_. `importSource` is more than just the new `pragma`, it also handles the fancy auto-import magic. This change makes it unnecessary to import your own custom lib (not just React) into each JSX file.
- aylmao 6y agoJSX has always been SGML/XML-inspired, but not SGML/XML compliant, so nothing is changing there. And the thing is, even if it were, what a parser/compiler does to represent a language is its own completely independent thing. At one point I had to use XML in JS (back in the day, haha). I parsed the XML and represented each node as a single object, with `__name` and `__children`. They were "one dimension" in my representation, but also literally a compliant XML parser— more compliant than JSX.
- lucideer 6y ago> a parser/compiler does to represent a language is its own completely independent thing This isn't really true of JSX; I'd suggest giving it a try to see exactly how the system works. To summarize, there are 3 parts of this discussion: 1. The JSX syntax (part of the JSX spec.) 2. The JSX transform (part of the JSX spec. & what parser/compiler must represent the language as) 3. The template function implemention: 100% independent and can represent nodes any way they want In your comment you're imagining a system where 2 & 3 are coupled, whereas this isn't how the JSX world works. With JSX, 1 & 2 are coupled, only 3 is independent.
- aylmao 6y ago> 2. The JSX transform (part of the JSX spec. & what parser/compiler must represent the language as) Ah, ok I see where this misunderstanding stems from. See, this is not part of the spec. With JSX, there's a very popular transpiler (Babel's), but it's by no means the only one or even "the official one". The spec actually lists three, and mentions [1]: > "These are a set of transpilers that all conform to the JSX syntax but use different semantics on the output: [...]" JSX is most commonly used with React, so if you're making a JSX transpiler it makes sense to make your default output work with React. This is by no means part of the definition of JSX though or a spec requirement. [1] https://facebook.github.io/jsx/ https://facebook.github.io/jsx/
- bryanrasmussen 6y agoI don't understand your contention that the new transform removes the flexibility of how other libraries could provide an element factory method? Do you mean that before JSX could be compiled to createElement and some other library's createElement could be used? If so I would ask how often does that actually happen? I would assume that any library that wanted to consume JSX would have their own JSX parser and compile to whatever structure that library wanted? on edit: I guess you went through that in the other comments, and your worries are at least partially handled by the changes to Babel?
- lucideer 6y ago> Do you mean that before JSX could be compiled to createElement and some other library's createElement could be used? If so I would ask how often does that actually happen? Yes, this is quite common practice. Many non-React libraries support this, but it's also extremely easy to use with your own templating function (the implementation can be as little as 1 line long) > I would assume that any library that wanted to consume JSX would have their own JSX parser and compile to whatever structure that library wanted? Nope, this isn't how JSX works. For example, React does not contain a JSX parser. JSX syntax is transpired by a build tool: currently the two most popular build tools are TSC and Babel. Both support targeting a custom library or your own custom code instead of React (but only the function name can be customised, the function signature that JSX is transformed to, as discussed in this article, is not customisable)
- bryanrasmussen 6y agoOk thanks, goes against my assumptions of how I would implement a JSX consuming library, but I guess there are probably lots of good reasons (performance, less code) why people do it this way and, as can happen, my assumptions probably wouldn't stand the test of actual implementation.
- AgentME 6y agoReact components access the children value through the children property of the props object, so it's not just an implementation detail. It's part of the component API. I think the similarity between the children value and other props is useful, to emphasize how any prop can contain child JSX elements. There's nothing special to the children value besides some syntax sugar. You can pass JSX elements to any other prop too.
- lucideer 6y agoYou're right it's part of the React component API but JSX is a spec. independent of React. The React component API is not part of JSX (and has little bearing on it).