-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support <> standalone fragment syntax #84
Comments
<>
standalone fragment syntax
cc @SanderSpies, if I recall you have something like this in Reason. How did it work out? |
@smrq let me reverse position (not the devil's advocate ;) here and say that React 16.x now allows us to do that (by explicitely setting |
The key thing is one issue that follows a very specific heuristic. It may not be enough to warrant new syntax. It might be possible to find other ways. The more convincing argument to me is the ability to nest text content and dropping the comma separator. return <>
Hello <strong>World</strong>!
</> vs. return [
"Hello ", <strong>World</strong>, "!"
] Another variant would be to drop the comma between JSX elements in arrays. This doesn't solve the text content issue though. Maybe that's just an argument for dropping JSXText #35? return [
<Foo />
<Bar />
<Baz />
] vs. return [
<Foo />,
<Bar />,
<Baz />,
] |
One thing that would be neat is that you sometimes would like to put a key on a whole fragment. var dynamicList = items.map(item => {
if (item.type === Foo) {
return <>
<Foo />
<Bar />
</>;
}
return <Foo key={item.id} />;
}); In the proposed var dynamicList = items.map(item => {
if (item.type === Foo) {
return <Frag key={item.id}>
<Foo />
<Bar />
</Frag>;
}
return <Foo key={item.id} />;
}); This can be implemented today in React as a component. |
I'll also point out that non-React usage of this would also greatly benefit (like Mithril + |
The issue with Frag is that it is in the same namespace as regular components. How about Or this might work: |
What about something like |
Another proposal was to use namespaces. <react:fragment>
<Child />
<Child />
</react:fragment> But if we were to do this, should we go all-in? For example <div react:key="1" react:ref={fn} /> But this is awkward to assign when defining element config as plain object. |
This blocks HTML from ever defining it. Kind of like MooTools killed |
I like the namespacing idea. |
A few more ideas. <@fragment>
<Child />
<Child />
</@fragment> <$>
<Child />
<Child />
</$> |
Or, use const Frag = ({children}) => children React could provide this as a named export of course. I really like how obvious the |
I like this. <*>
<Child />
<Child />
</*> It kind of implies "multiple elements" and you can put a key on it if you want. var dynamicList = items.map(item => {
if (item.type === Foo) {
return (
<* key={item.id}>
<Foo />
<Bar />
</*>
);
}
return <Foo key={item.id} />;
}); |
Haha I guess that won't work because of comments 😛 |
you could always end it with |
The reason I dislike typing "fragment" is because it's one of its kind. It's not like we're going to add more primitives like this. It's pretty fundamental by itself, rather than a part of some bigger API of core primitives. So it's annoying to squat on a whole namespace or create a special export just for a single thing. If you see There's two counter arguments. One is making it explicit makes it very easy to Google. Googling characters is not very pleasant (although maybe they fixed it). The other counter argument is we may in fact add more primitives. Such as yields and coroutines. But those seem to be solved better on syntax level than by adding special cases of elements. Especially since they're not even producing elements. |
I mean you could support
Personally. Despite its strangeness, I kind of like return <key="foobar">
<div />
</>; return (
<key="foobar">
<div />
<key="barfoo"> // someone could do this, but I'm not sure why they would
<strong />
</>
<FooBar />
</>
); Or is it too strange to stomach? |
Can someone explain why this wouldn't work?
Which could just be sugar for
Afaik it doesn't conflict with anything + doesn't need new syntax. |
@rikkit Even if that would work it wouldn't solve |
Here's an example of ambiguity this would introduce. return (
<div>Element 1</div>
) this is just a paren in text node
<div>Element 2</div>
); Note how text nodes (which are normally valid in JSX) become broken as a result. It's not clear if There are similar issues with newlines, braces, etc. All of those are OK in JSX but become ambiguous if we don't have a shared JSX ancestor. |
I'd just like to point out that .net/razor templating language introduces I think I'd prefer either A user-space |
@mnpenner This is the JSX-namespace though, and not the HTML-namespace. Also, by reserving the EDIT: "JSX-namespace" as in it applies to all current and future JSX/React renderers, not just HTML.
Unless JSX ends up reserving an element name then the IDEs need to update the autocomplete and syntax highlighter anyway. |
What do you mean? Oh... you mean for people that are using JSX for non-ReactDOM? Yeah, okay. I see your point. Using
Anyway, I'm not sure what the best solution is then. |
BTW, I like the namespace best:
Here's how I feel it could be handled, via modifications to
|
Is this syntax necessary? Just leave it up to the community to establish a convention. See: |
@gajus Its semantics differ from "true fragments" and has additional performance overhead. |
Sorry, rushed into discussion. Regardless, I disagree that a new syntax (such as Would it not be better to reserve a component name for the use case? (e.g. Aux, Fragment or whatever else) and treat it specifically. Otherwise, every new edge case requirement such as this will require a new syntax. Syntax such as |
Yes, a namespace is one way of not stepping on anyone's toes; I'd hope that a shortening like |
@rattrayalex To clarify, the namespace usage would be optional with my proposal. |
@rattrayalex For React it seems it will be synonymous with |
Which sounds reasonable. Then just have a babel rule that interprets the matching component in a special way. |
Workaround that works with React v16.0.0: import React from 'react';
import { render } from 'react-dom';
class VirtualDiv extends React.Component {
render() {
return this.props.children;
}
}
const App = () => (
<VirtualDiv>
<h2>Hello</h2>
<p>Second element</p>
</VirtualDiv>
);
render(<App />, document.getElementById('root')); Preview: https://codesandbox.io/s/0m7204mlw Oops, there's |
This has actually already been proposed higher up, and it has the
disadvantage of introducing an empty level in the tree, slightly impacting
performance.
…On Sat, Oct 14, 2017 at 7:39 PM Jake Goulding ***@***.***> wrote:
Which has the very succinct ES6 form:
const Fragment = ({ children }) => children;
const App = () =>
(
<Fragment>
<h2>Hello</h2>
<p>Second element</p>
</Fragment>
);
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#84 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AADWlr4X5hL5zHxDNLrmZG8maUGZlft9ks5ssPHpgaJpZM4O4LMl>
.
|
Excuse my ignorance on the subject, but instead of introducing new syntax, could we not make JSX introduce a transparent wrapper around static arrays that allows consuming libraries to know for sure that they are static? Then the warnings for keys can be discarded with no new syntax, no performance implications—everyone is happy, world peace is attained, etc. Example: function render() {
return [
<div>One</div>,
<div>Two</div>,
<div>I am a snowflake!</div>
]
} Would result in: function render() {
return React.StaticArray(
React.createElement( "div", null, "One"),
React.createElement( "div", null, "Two"),
React.createElement( "div", null, "I am a snowflake!")
);
} Where export class StaticArray extends Array {
constructor(...args) {
super(...args);
}
__static__ = true
} |
@JonDum Fragments are not really about the data representation, it's to have a useful syntax for this problem: #84 (comment) |
@JonDum In your example, how would the transpiler know that it should be a |
This is a static fragment that is passed to a function that expects some type of element and wraps it. render() {
const wrapWithContainer = (content) => <div>{content}</div>;
return (
<div>
{wrapWithContainer([
<span>A</span>,
<span>B</span>
])}
</div>
);
} This is an array of nodes passed to a function that expects an array and does array operations on it. render() {
const processNodes = (nodes) => nodes.map((node) => <div>{node}</div>);
return (
<div>
{processNodes([
<span>A</span>,
<span>B</span>
])}
</div>
);
} How do you tell the difference? |
You can use the AST to check for the few scenarios where it could be processed, like ensure we're in the render function, we're not a child of Example:
Quick n' dirty tests: https://github.com/JonDum/jsx-static-array-plugin I'm sure I'm missing cases, but the concept is there. Maybe at this point though it's cleaner to just auto-key the elements instead of wrapping in a special |
I created a component to handle this that I called a shadow wrapper. I wrap my child components in it instead of DIVs. I'd be interested to know it's limitations. I'm fairly new to React. |
@clemmy @sebmarkbage @smrq Should this issue be closed now that #93 and #94 are merged in? |
@matt-landers That's a good question - the difference is in the state preservation behavior when using a class or functional component to wrap it. Although the shadow wrapper works for common cases, it doesn't preserve state in some edge cases such as rendering something like
and then having it be inside a fragment in a subsequent render
Cases can be found here. Aside from that, there are some optimizations that can be done by putting the React Fragment export inside the core library. |
@clemmy Thanks for the response. Looking forward to using the new spec. |
This syntax (or similar) has been brought up in a number of comments across various issues already, but as far as I can tell has no standalone proposal.
The syntax is:
This is equivalent to an array, except that because the structure of the array is statically known, keys could be automatically assigned to each child.
I think a lot of people may mistakenly think React 16.x can already do this as a result of the new feature to return multiple components from
render
. I suspect the lack of this syntax might become even more of a pain point with that release.(Correct me if I'm wrong or should clarify anything further. I'm just making the issue because it seems there should have been one already.)
The text was updated successfully, but these errors were encountered: