Skip to content
Please note that GitHub no longer supports Internet Explorer.

We recommend upgrading to the latest Microsoft Edge, Google Chrome, or Firefox.

Learn more
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 (or document non-support) for Fragments #946

Closed
alexkrolick opened this issue Nov 27, 2017 · 41 comments
Closed

Support (or document non-support) for Fragments #946

alexkrolick opened this issue Nov 27, 2017 · 41 comments
Labels

Comments

@alexkrolick
Copy link

@alexkrolick alexkrolick commented Nov 27, 2017

reactjs/reactjs.org#345

React is adding a top-level React.Fragment export that transpiles to JSX as:

<>
  <li>Stuff</li>
  <li>Things</li>
</>

React.createElement(React.Fragment, {}, ...)

Would Preact be able to support fragments or provide some type of fallback?

@leeoniya

This comment has been minimized.

Copy link

@leeoniya leeoniya commented Nov 27, 2017

@developit

This comment has been minimized.

Copy link
Member

@developit developit commented Dec 3, 2017

+ #929. I might be working on something. In the meantime, it's impossible to really fall back to anything other than inserting a <span> since the diff engine is incapable of dealing with arrays of nodes where there are currently only single nodes supported (components roots).

You can "patch" fragments by setting Babel's pragmaFrag option to "span":

"plugins": [
  ["transform-react-jsx", {
    "pragma": "h",
    "pragmaFrag": "\"span\""
  }]
]
@developit developit added the duplicate label Dec 3, 2017
@koutsenko

This comment has been minimized.

Copy link

@koutsenko koutsenko commented Dec 19, 2017

They introduces < Fragment > component also. In some cases (e.g. old eslint rules) its more preferrable...

@developit

This comment has been minimized.

Copy link
Member

@developit developit commented Dec 20, 2017

If you want to use Fragment faked out for now, just do this:

React.Fragment = 'x-fragment';
@CaptainN

This comment has been minimized.

Copy link

@CaptainN CaptainN commented Jan 4, 2018

Where would one put that? React.Fragment = 'x-fragment'; - somewhere in a webpack config?

@kurtextrem

This comment has been minimized.

Copy link

@kurtextrem kurtextrem commented Jan 6, 2018

@CaptainN I guess in index.js or something similar.

toshiaki-gohei added a commit to toshiaki-gohei/gohei-mochi that referenced this issue Jan 24, 2018
preact is good, but
* have not fixed yet? too late...
  preactjs/preact#915
* want to use JSX Fragments
  preactjs/preact#946
  @developit
  It's on the ToDo list, but extremely difficult given Preact's current design.
@adamduncan

This comment has been minimized.

Copy link

@adamduncan adamduncan commented Feb 5, 2018

Is lack of support for Fragment why we see <undefined> elements in output?

screen shot 2018-02-05 at 19 08 00

Would reassigning React.Fragment to 'x-fragment' be needed in the component that makes use of Fragment, and still result in extraneous custom elements in the DOM? I.e.

import React, { Fragment } from 'react'
React.Fragment = 'x-fragment'
@arusanov

This comment has been minimized.

Copy link

@arusanov arusanov commented Feb 15, 2018

@developit any estimate on this feature?

@phun-ky

This comment has been minimized.

Copy link

@phun-ky phun-ky commented Feb 20, 2018

What is the status of this @developit ? or can this be supported in preact-compat?

@developit

This comment has been minimized.

Copy link
Member

@developit developit commented Feb 23, 2018

Sorry for the radio silence! Right now we just have the hack I posted.

Fragment support requires a complete re-architecture of Preact, which I've been working on. I will be making that work public soon.

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Feb 25, 2018

@developit Any chance to help out with that? I'd love to get involved 🎉

@developit

This comment has been minimized.

Copy link
Member

@developit developit commented Mar 1, 2018

@marvinhagemeister I just added you as a contributor here. Ping me on slack!

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Mar 4, 2018

Just got contributor access and went through a few minor PRs to get started. Implementing Fragments shouldn't be that hard. I did a preview implementation for my preact-server renderer here https://github.com/marvinhagemeister/preact-server-renderer/pull/14/files . Basically a Fragment is a plain component which is treated differently at the render phase.

Before we can tackle it there are a few tasks, which will make adding them much easier:

  1. get dependencies up to date - done
  2. update to babel 7 because of <>foo</> jsx tags. (Fragments aren't much fun without them)
  3. actually implement support for fragments.

I'm currently working on the first to and hopefully we can tackle point 3 soon 🎉

@phun-ky

This comment has been minimized.

Copy link

@phun-ky phun-ky commented Mar 5, 2018

@marvinhagemeister nice work! but I personally feel that we could skip 2. for this fix if possible. I really hope that this fix could be in place before babel@7 enters the playing field, since it's still in beta

@EmielM

This comment has been minimized.

Copy link

@EmielM EmielM commented Mar 5, 2018

I concur with @phun-ky. In my projects we're not using React.Fragment often, but only sporadically where it aids in getting a simpler (flex) layout (ie. preventing extra wrapping). In those few instances, using <React.Fragment> is preferred as it makes more explicit what's going on.

@adamduncan

This comment has been minimized.

Copy link

@adamduncan adamduncan commented Mar 5, 2018

Nice one @marvinhagemeister. +1 on bypassing point 2. It's not a showstopper after a bit of destructuring.

import React, { Fragment } from 'react'

<Fragment>
  ...
</Fragment>
@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Mar 5, 2018

I guess I should have phrased the task list differently.

Of course both 1. + 2. are not hard requirements to add support for Fragments. These are just tasks that I'd love to get in before tackling them, that's all.

@georgiemathews

This comment has been minimized.

Copy link

@georgiemathews georgiemathews commented Mar 27, 2018

@marvinhagemeister what’s the progress on this? Is there any way I can help out?

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Mar 28, 2018

@georgiemathews We do have Fragments working in a private branch, but we haven't had the time to make it work with hydration yet.

@prakashsanker

This comment has been minimized.

Copy link

@prakashsanker prakashsanker commented Apr 9, 2018

@marvinhagemeister pretty excited for this - when do you think this will merge?

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Apr 30, 2018

@prakashsanker Progress can be tracked here: #1080 🎉

@andrewkesper

This comment has been minimized.

Copy link

@andrewkesper andrewkesper commented Aug 9, 2018

I'm able to achieve the desired effect by returning an array of elements.

Here's a simple example of an HTML definition list:

export default class Glossary extends Component {
  state = { 
    glossary: [
      {term: 'HTML', description: 'Hypertext Markup Language'},
      {term: 'JS', description: 'JavaScript'},
      {term: 'CSS', description: 'Cascading Style Sheet'}
    ]
  };
  render({ }, { glossary }) {
    return (
      <dl>
        { glossary.map( g => (
          [ <dt>{g.term}</dt>, <dd>{g.description}</dd> ] // Here is the magic
        )) }
      </dl>
    );
  }
}

HTML output:

<dl>

  <dt>HTML</dt>
  <dd>Hypertext Markup Language</dd>

  <dt>JS</dt>
  <dd>JavaScript</dd>

  <dt>CSS</dt>
  <dd>Cascading Style Sheet</dd>

</dl>

Working demo here

@apfelbox

This comment has been minimized.

Copy link

@apfelbox apfelbox commented Aug 9, 2018

@andrewkesper that works if you are inside a JSX.Element. What fragments explicitly allow is something else: returning "an array" directly from render(), so that you don't need to have a single root element on components (at least non that ends up in the DOM).

@qodesmith

This comment has been minimized.

Copy link

@qodesmith qodesmith commented Aug 24, 2018

In React it seems we can make our own Fragment component like this:

import React from 'react'
const Fragment = ({ children }) => React.Children.toArray(children)
export default Fragment

Could the same thing be done with Preact?

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Aug 24, 2018

No, current preact expects a DOM node per vnode. This is not true for Fragments where the whole point of them is to not render anything into the DOM. So this is not easily doable (if at all) with the current architecture.

That said we have merged the PR for Fragments into our development repo last week. Fragments will be part of the next major release🎉

It is not available to the public yet and we don't have a release estimate for now. It's progressing nicely and we are currently working through an ever shrinking number of failing test cases and ensuring that all known bugs in the next version are fixed.

@dmbdesignpdx

This comment has been minimized.

Copy link

@dmbdesignpdx dmbdesignpdx commented Sep 15, 2018

Hi, I know this is late, but I just wanted to share a possible temporary solution until Fragments are included. At least this has worked for me...

function ListItems() {
  return ([
    <li></li>,
    <li></li>
  ])
}

class List extends Component {
  ...
  render() {
    return (
      ...
      <ListItems />
      ...
    )
  }
}

The <ListItems />, of course, will result in becoming <undefined></undefined>.
BUT, if you change it to a function call within a JSX expression:

class List extends Component {
  ...
  render() {
    return (
      ...
      { ListItems() }
      ...
    )
  }
}

It will work as expected.

Hope that helps someone!

@Ayc0

This comment has been minimized.

Copy link

@Ayc0 Ayc0 commented Oct 30, 2018

@marvinhagemeister do you know when the new version of Preact with Fragments will be released?

@calebeby

This comment has been minimized.

Copy link
Contributor

@calebeby calebeby commented Oct 31, 2018

@andidevi

This comment has been minimized.

Copy link

@andidevi andidevi commented Nov 1, 2018

This workaround is closer to React.Fragment and will keep your project compatible with React:

import React from 'react';
import pure from 'recompose/pure';
const Fragment = React.Fragment || pure(({children}) => children);
@andidevi

This comment has been minimized.

Copy link

@andidevi andidevi commented Nov 2, 2018

There's a bug in preact witch will prevent the rendering of the remaining parts of an children-arrays, if they contain a null value.

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Nov 2, 2018

@andidevi Do you have a simple test-case or snippet that we can use to reproduce the issue you are experiencing?

@IngwiePhoenix

This comment has been minimized.

Copy link

@IngwiePhoenix IngwiePhoenix commented Dec 5, 2018

So... What's the current status on this? I am currently looking at which library to choose - and I'd rather choose Preact, due to it's size.

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Dec 5, 2018

We're getting close to a release, but as with everything the last few percents are the hardest. We basically have 1 bug left and need to get compat ready.

@qodesmith

This comment has been minimized.

Copy link

@qodesmith qodesmith commented Dec 5, 2018

Very excited about this :)

@kontrollanten

This comment has been minimized.

Copy link

@kontrollanten kontrollanten commented Dec 5, 2018

I've created a small babel plugin to add support for React.Fragment. What it does is simply to remove the React.Fragment element. I've got it working with material-ui/icons. I'll upload it to npm if it's wanted, but now you can use by reference to GH. I've written a readme at https://github.com/kontrollanten/babel-plugin-preact-fragment

@reznord

This comment has been minimized.

Copy link
Member

@reznord reznord commented Mar 4, 2019

Fragments are implemented in #1302 (will be available in an alpha release pretty soon)

@reznord reznord closed this Mar 4, 2019
@andyfurniss4

This comment has been minimized.

Copy link

@andyfurniss4 andyfurniss4 commented Mar 21, 2019

Any idea when this will be out of alpha?

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Mar 21, 2019

@andyfurniss4 At this point we can't give a specific timeframe on when we'll be out of alpha. We'll likely move to beta when Fragments are rock solid 👍

@jessicabyrne

This comment has been minimized.

Copy link
Contributor

@jessicabyrne jessicabyrne commented Mar 26, 2019

We have a project written in Preact that is referencing a component from another library (written with React 16) that does not render at all on first render (it will appear if I force a rerender). There is no error or stacktrace.
The component we reference looks like this:

const TheComponent = React.forwardRef((props, ref) => {
  const { ...rest } = props;

  return (
    <div {..rest} />
});

export default TheComponent;

Is this a known issue with Preact X? (which we are now on! 🎉 )
What is the most reliable work-around for this right now? I've tried adding React.Fragment = 'x-fragment' at the top of the referencing file (and index.jsx), but it didn't change anything.

@marvinhagemeister

This comment has been minimized.

Copy link
Member

@marvinhagemeister marvinhagemeister commented Mar 26, 2019

@jessicabyrne The issue you are describing may not be related at all to Fragments. Can you open a new one issue where we can get to the bottom of it together? Maybe we can even reproduce the issue in a codesandbox.

@jessicabyrne

This comment has been minimized.

Copy link
Contributor

@jessicabyrne jessicabyrne commented Mar 26, 2019

@marvinhagemeister I'm convinced it's to do with Fragments after doing some more investigating. If I change the referenced code to use a div instead, the component renders fine. I did open a new issue though, we can move the conversation there :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.