4

React is getting me in trouble with flexbox because of the wrapping div in a component's render function is throwing off my flex-directions.

From what I understand about React, all the component's jsx elements should be wrapped up in a single div. For example this works:

return (
    <div className="com-container">
       <div className="other-stuff">
       </div>
    </div>
)

whereas this doesn't:

return (
    <div className="com-container">
    </div>
    <div className="other-stuff">
    </div>
)

Yet this is making things hard with flexbox rows and columns. For example say we had this flex relationship.

<Parent Column Component /> //vertical flex
  <ChildRowComponent1 />    //horizontal flex
  <ChildRowComponent2 />    //horizontal flex
  <ChildRowComponent3 />    //horizontal flex

But ChildRowComponent2 & 3 can be swapped out dynamically - which causes me to refactor by putting ChildRowComponent2 & 3 in their own component but since all rendering must be wrapped up in a single div I get this extra div that messes up the flex directions.

<Parent Column Component />  //vertical flex
  <ChildRowComponent1 />     //horizontal flex
  <div>                      
    <ChildRowComponent2 />   //horizontal flex now broken
    <ChildRowComponent3 />   //horizontal flex now broken
  </div>

Question:

Is there a flexbox trick to handle these cases or am I just doing something wrong with how I'm structuring my components?

mik01aj
  • 11,928
  • 15
  • 76
  • 119
Nick Pineda
  • 6,354
  • 11
  • 46
  • 66

2 Answers2

2

Fragments solve this problem. You don't need any extra <div> elements when wrapping child elements. This won't add extra nodes to the DOM.

return (
 <React.Fragment>
    <div className="com-container">
    </div>
    <div className="other-stuff">
    </div>
 <React.Fragment>
)

React Fragment Documentation

Lanil Marasinghe
  • 2,785
  • 24
  • 24
1

Instead of creating a component that groups ChildRowComponent2 & 3, you can make it a function that returns a list. Then you can do this in your Parent component:

  render: function() {
    return (
      <div className="main-container">
        <ChildRowComponent1 />
        { this.renderOtherChildren() }
      </div>
    )
  },
  renderOtherChildren: function () {
    var result = [];
    if (this.props.shouldHaveSecondChild) {
      result.push(<ChildRowComponent2 key={ 2 } />);
    }
    if (this.props.shouldHaveThirdChild) {
      result.push(<ChildRowComponent3 key={ 3 } />);
    }
    return result;
  },

If you're wondering why do you need the key prop, here is an explanation.

mik01aj
  • 11,928
  • 15
  • 76
  • 119
  • I'll experiment with this and let you know how it goes. Open to any other workarounds people have come up with. – Nick Pineda Oct 06 '15 at 14:13
  • Also @m01, could you elaborate on your answer just a little more? I've never seen another function that is potentially returning jsx, or other components, so seeing the syntax of that would be quite useful. – Nick Pineda Oct 06 '15 at 14:20
  • I added this to the answer. – mik01aj Oct 06 '15 at 14:37
  • I'm reading the link you posted now. I'll try it out and let everyone know how it turned out :) – Nick Pineda Oct 06 '15 at 14:39
  • One last clarifying question- this.props.children will change with routing so it's value, for example, could either be or . How could we check for the routing cases in your renderOtherChildren method? – Nick Pineda Oct 06 '15 at 14:53
  • 1
    Well, I think that you could actually refactor your router so that instead of rendering the components, it would just *return the information* about which components should be visible. Then your `Parent` component would get this information in `props` and handle accordingly. (Disclaimer: I never used react-router.) Btw: `this.props.children` is a list (e.g. `[, ]`), so you can use it as you would use the output from my `renderOtherChildren` function. – mik01aj Oct 06 '15 at 14:59