Skip to content
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

reactjs/react.dev#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
Copy link

#939

@developit
Copy link
Member

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\""
  }]
]

@koutsenko
Copy link

koutsenko commented Dec 19, 2017

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

@developit
Copy link
Member

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

React.Fragment = 'x-fragment';

@CaptainN
Copy link

CaptainN commented Jan 4, 2018

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

@kurtextrem
Copy link

@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
Copy link

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
Copy link

@developit any estimate on this feature?

@phun-ky
Copy link

phun-ky commented Feb 20, 2018

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

@developit
Copy link
Member

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
Copy link
Member

marvinhagemeister commented Feb 25, 2018

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

@developit
Copy link
Member

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

@marvinhagemeister
Copy link
Member

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
Copy link

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
Copy link

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
Copy link

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
Copy link
Member

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
Copy link

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

@marvinhagemeister
Copy link
Member

@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
Copy link

prakashsanker commented Apr 9, 2018

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

@marvinhagemeister
Copy link
Member

@prakashsanker Progress can be tracked here: #1080 🎉

@andrewkesper
Copy link

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
Copy link

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
Copy link

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
Copy link
Member

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
Copy link

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
Copy link

Ayc0 commented Oct 30, 2018

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

@calebeby
Copy link
Contributor

https://twitter.com/marvinhagemeist/status/1056229900158451712

@andidevi
Copy link

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
Copy link

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
Copy link
Member

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

@IngwiePhoenix
Copy link

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
Copy link
Member

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
Copy link

Very excited about this :)

@kontrollanten
Copy link

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
Copy link
Member

reznord commented Mar 4, 2019

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

@reznord reznord closed this as completed Mar 4, 2019
@andyfurniss4
Copy link

Any idea when this will be out of alpha?

@marvinhagemeister
Copy link
Member

@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
Copy link
Contributor

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
Copy link
Member

@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
Copy link
Contributor

@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
Labels
Projects
None yet
Development

No branches or pull requests