Skip to content

Add fragment API to allow returning multiple components from render #2127

Closed

Description

@AdamKyle

Note from maintainers:

We know this is an issue and we know exactly what set of problem can be solved. We want this too but it is a hard problem with our current architecture. Additional comments expressing desire for this feature are not helpful. Feel free to subscribe to the issue (there's button in the right hand column) but do not comment unless you are adding value to the discussion. "Me too" and "+1" are not valuable, nor are use cases that have already been written in the comments (e.g., we know that you can't put <tr> or <dd> elements with a <div>).


Consider the following:

var ManagePost = React.createClass({

  render: function() {
    var posts = this.props.posts

    var something;
    var somethingelse;

    var row = posts.map(function(post){
      return(
        <div>
          <div className="col-md-8">
          </div>
          <div className="cold-md-4">
          </div>
        </div>
      )
    });

    return (
        {row}
    );
  }

});

If you remove the <div></div> in the map, you get the following error: Adjacent XJS elements must be wrapped in an enclosing tag

it isn't till I re-add the surrounding, and rather pointless, divs that it compiles with out issue. I am running 0.11.1

Is this being addressed? It adds extra, and again - IMO - useless and pointless html to the page, that while harming nothing - looks messy and unprofessional. Maybe I am just doing something wrong, please enlighten me if I am.

Activity

  1. chenglou commented on Sep 2, 2014

    @chenglou
    Contributor

    Because when you don't put the wrapper, it desugars to this:

    return React.DOM.div(...)React.DOM.div(...)

    Which doesn't make syntactical sense. The jsx compiler page might help if you need a visual mapping.

    That being said, it's possible to desugar this to [div, div] instead. This is hard, somewhat controversial and won't be implemented in a near future.

  2. sophiebits commented on Sep 2, 2014

    @sophiebits
    Contributor

    (I don't think it's particularly controversial but it does add code complexity and hasn't been done yet.)

  3. chenglou commented on Sep 2, 2014

    @chenglou
    Contributor

    IIRC @syranide has a few comments on this

  4. syranide commented on Sep 2, 2014

    @syranide
    Contributor

    @chenglou Hehe.

    I had a brief chat about it with chenglou a little while ago, I don't really lean one way or the other at the moment. I see a lot of hidden dangers in allowing a composite components to return multiple components and it breaks a lot of intuitive assumptions, but I don't know of any (right now) good practice use-cases that would obviously benefit from this.

    The simplicity of returning at most one component means that it's very easy to reason about what you see, if not, <table><TableHeader /></table> could actually render any number of rows, you have no way of knowing other than inspecting TableHeader and whatever composite components it returns.

    I feel like being able to return multiple components only moves the responsibility of wrapping components as necessary from the "composite component" to whatever "renders the composite component". The component "that renders composite component" rarely has or should have the knowledge of whether to wrap composite components or not, whereas children are more likely to have knowledge of their parents.

    But perhaps it's simply a case of developer responsibility. There may be good use-cases for both and we should just look past the inevitable misuse.

    @sebmarkbage Probably has a few comments too :)

  5. sebmarkbage commented on Sep 2, 2014

    @sebmarkbage
    Contributor

    We will probably never allow that syntax implicitly. You would need a wrapper like

    <>
      <div className="col-md-8">
      </div>
      <div className="cold-md-4">
      </div>
    </>

    OR

    [
      <div className="col-md-8">
      </div>,
      <div className="cold-md-4">
      </div>
    ]

    However, even this doesn't work. Often, it's probably for the best. It can be confusing for consuming components when a child might expand into multiple elements.

    But, really, the only reason we don't support this right now is because it's hard to implement. Hopefully, we'll be able to support it sometime in the future but probably not short term. Sorry. :/

  6. AdamKyle commented on Sep 3, 2014

    @AdamKyle
    Author

    can this not affect things like jquery or other libraries that target specific elements, so if you do something like $('#id-name').children(), the following:

    <div id="id-name">
      <div>
        <div class="class-name">
        </div>
      </div>
    </div>

    the <div> and <div class="class-name"> would be selected in this case. (If I understand this properly)

  7. DAddYE commented on Oct 13, 2014

    @DAddYE

    It affects also css selectors in the very same way @AdamKyle posted before.

  8. srph commented on Nov 16, 2014

    @srph
    Contributor

    Any updates on this issue?

  9. gabssnake commented on Dec 1, 2014

    @gabssnake

    Spent a couple of minutes understanding why my component didn’t work. I feel like there should be a notice somewhere, maybe I missed it ? Maybe it is obviously wrong to try :

    var Optimistic = React.createClass({
      render: function() {
        return ( 
          <h1>{this.props.name} loves React</h1>
          <p>React doesn’t. Idea: sprinkle some divs here and there.</p>
        );
      }
    });
    
    React.render(
      <Optimistic name="Peter" />,
      document.getElementById('myContainer')
    );
  10. sophiebits commented on Dec 1, 2014

    @sophiebits
    Contributor

    @gabssnake You should have gotten a JSX compile error with the error "Adjacent XJS elements must be wrapped in an enclosing tag"; did you not see the error or was it not clear in its explanation?

  11. gabssnake commented on Dec 1, 2014

    @gabssnake

    Thank you for your answer @spicyj. Well, I meant a notice in the React documentation. Yes, the console did show an error, but the need to wrap didn’t make sense to me at first. That is why I searched and got here.

  12. GetContented commented on Jan 28, 2015

    @GetContented

    I've had this pain as well... particularly painful for my designer, as a matter of fact. It'd be kind of nice if a component could output a node (therefore node-list or fragment) instead of an element.

  13. gaearon commented on Jan 28, 2015

    @gaearon
    Contributor

    Just saying.. I'm not advocating returning multiple children from component but I'd love to do that in render* methods that I extract from render:

      render: function () {
        return (
          <div className={this.getClassName()}
               style={{
                 color: this.props.color,
                 backgroundColor: this.props.backgroundColor
               }}>
            {condition ?
              this.renderSomething() :
              this.renderOtherThing()
            }
          </div>
        );
      },
    
      renderSomething() {
        return (
          <>
            <div className='AboutSection-header'>
              <h1>{this.props.title}</h1>
              {this.props.subtitle &&
                <h4>{this.props.subtitle}</h4>
              }
            </div>,
    
            {hasChildren &&
              <div className='AboutSection-extra'>
                {this.props.children}
              </div>
            }
          </>
        );
      }

    But I should probably just shut up and use keys.

  14. syranide commented on Jan 28, 2015

    @syranide
    Contributor

    @gaearon You can do that already though, you just need to return an array for now (which is a bit cumbersome though yes) ... buuuuut, you can work around that, I have hacked my own <Frag> component which is translated to an array (overloaded React.render) ... you could also do return <NoopComp>...</NoopComp>.props.children I assume, if you want to avoid hacks.

    EDIT: My bad, I overloaded React.createElement not React.render.

  15. gaearon commented on Jan 28, 2015

    @gaearon
    Contributor

    The problem with arrays is they trip our designer. Need commas, explicit keys.

  16. 128 remaining items

  17. diligiant commented on Aug 15, 2017

    @diligiant

    @JesperTreetop & @zwily, @gaearon explained it way better than I did ;)

    Once you know, it's no big deal but as we all want React to thrive, I was just saying…

  18. smrq commented on Aug 15, 2017

    @smrq

    @gaearon Is there another issue for the <> syntax proposal that we can watch instead of further discussion on this issue? I searched around but I wasn't able to find one.

  19. veged commented on Aug 15, 2017

    @veged

    @smrq +1 to question — I follow everything about those awkward limitations (one-to-one rendrer() result, keys and JSX syntax or fragments) but the only ticket I know is react/jsx#65

    I also suppose that fibers gonna fix issue with keys at all — but looks like it's unfulfilled dream

  20. sophiebits commented on Aug 15, 2017

    @sophiebits
    Contributor

    Keys aren't an "issue". :) They're a fundamental and necessary part of any view framework that allows you to create dynamic lists.

    See https://facebook.github.io/react/tutorial/tutorial.html#keys for a more detailed explanation.

  21. veged commented on Aug 15, 2017

    @veged

    @spicyj actually it is an «issue» since it cause extended energy spendings from developers and there is fundamental possibility to program view framework without such requirement (for example https://github.com/dfilatov/vidom)

  22. goto-bus-stop commented on Aug 15, 2017

    @goto-bus-stop

    there is fundamental possibility to program view framework without such requirement (for example https://github.com/dfilatov/vidom)

    vidom does use keys in collections though. It might technically work without it but it would likely be much slower. React could also technically work without keys, but it'd be quite unexpected to find that half of your components have to update when you remove a single item from a list. With keys, only one item is unmounted.

  23. veged commented on Aug 15, 2017

    @veged

    @goto-bus-stop vidom can use keys, but they are not required and without them only really big cases with a lot of updates can cause real performance problems

    so I consider this part as possible optional (as, for example, shouldComponentUpdate) which can be used for ferformance tweaks in individual cases

  24. brigand commented on Aug 15, 2017

    @brigand
    Contributor

    @veged example of vidom struggling without keys.

    It has no idea it's supposed to reorder the elements, so it discards the instances on each render of the root component.

  25. leeoniya commented on Aug 15, 2017

    @leeoniya

    as someone who's quite familiar with the virtual-dom space [1]. i can say that:

    1. keys are necessary for predictable dom & state updates amongst similar siblings.
    2. keys are typically not an optimization, and - in fact - are usually the opposite.

    [1] https://github.com/leeoniya/domvm

  26. veged commented on Aug 15, 2017

    @veged

    however, the unambiguous issue here (as @gaearon described) is a fully static usage of arrays and the difference between static arrays and static JSX fragments

  27. veged commented on Aug 15, 2017

    @veged

    @brigand O have no doubt that reordering of state-full components may cause some issues ;-) but force every other cases (in my opinion more of them) to struggle for this... looks controversial

  28. gaearon commented on Aug 15, 2017

    @gaearon
    Contributor

    Keys are important to React. Even if they don't seem to matter in some case (e.g. because components below are all stateless) there is nothing preventing you or someone else on the team to add a stateful component (or even a plain DOM input) somewhere a few levels below in a few months. By then you might forget that you don't have keys, and thus reorders may cause the state (or input value) to be associated with a wrong item.

    This is why we encourage you to specify keys everywhere for dynamic lists. Not doing so leads to very hard-to-trace bugs, and we think it's better to spend extra ten seconds specifying the key than ten hours debugging why the state of a component several levels below gets messed up in some corner case.

    I fully agree it's inconvenient to specify keys when the list is known to be static and never reorders. You are welcome to discuss this on the JSX repo. If you can't find an issue for this, you are welcome to create a new one there.

    Since this thread has a lot of subscribers and the feature has been implemented I would like to lock it to avoid spamming a lot of people with notifications. I hope the clarifications above address your concerns, but if not, you are welcome to create a new issue for further discussion on a specific topic.

  29. locked and limited conversation to collaborators on Aug 15, 2017
  30. sophiebits commented on Aug 15, 2017

    @sophiebits
    Contributor

    @smrq created a proposal issue for <> syntax on the jsx repo: react/jsx#84.

  31. gaearon commented on Nov 28, 2017

    @gaearon
    Contributor

    We just released support for a new React.Fragment export and the associated <> syntax:
    https://reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions