React Fragments

Hi! I'm Ken.

I'm a full-stack product engineer.

I work at Stream, helping companies make apps with scalable and personalized activity feeds.

I'm a big fan of building dumb fun web stuff and wrenching on rusty old cars.

React Fragments

this is more of a "hey, these exist!" kind of talk than an "in-depth tips and tricks" talk

If you'd like to revisit this later:

Slides: ken.hoff.tech/slides/fragments

Context time!

I've been working on Winds 2.0!

Winds 2.0 is an RSS reader and podcast player that showcases activity feeds from Stream.

Check it out at https://getstream.io/winds/.

I'm sure you've all run into this before

class App extends Component {
    render() {
        return (
            <p>I would</p>
            <p>really like</p>
            <p>to render</p>
            <p>an array</p>
        );
    }
}

womp womp:

    Failed to compile.

    ./src/App.js
    Syntax error: Adjacent JSX elements must be wrapped in an enclosing tag (6:8)

        4 |         return (<p>I would
        5 |         </p>
        6 |         <p>
          |         ^
        7 |             really like
        8 |         </p>
        9 |         <p>

the "I didn't do any research and I need to hit my estimate" way

class App extends Component {
    render() {
        return (
            <div>
                <p>I would</p>
                <p>really like</p>
                <p>to render</p>
                <p>an array</p>
            </div>
        );
    }
}

(or)

class App extends Component {
    render() {
        return [
            <p>I would</p>,
            <p>really like</p>,
            <p>to render</p>,
            <p>an array</p>
        ];
    }
}

(notice the commas! because we're returning a JS object / array, it's okay.)

Dan Abramov / React folks say:

"this is 💩"

(well, sort of)

React v16.2.0 introduces Fragments

How to use a React Fragment

instead of

class App extends Component {
    render() {
        return [
            <p>I would</p>,
            <p>really like</p>,
            <p>to render</p>,
            <p>an array</p>
        ];
    }
}

we use

class App extends Component {
    render() {
        return (
            <React.Fragment>
                <p>I would</p>
                <p>really like</p>
                <p>to render</p>
                <p>an array</p>
            </React.Fragment>
        );
    }
}

an alternate method

depending on your tooling (build pipeline, linters, beautifiers, etc), this might also work

class App extends Component {
    render() {
        return (
            <>
                <p>I would</p>
                <p>really like</p>
                <p>to render</p>
                <p>an array</p>
            </>
        );
    }
}

(see, the blog post says that this is supported in some tools, but create-react-app doesn't support it yet, so use at your own risk)

the "theory" answer

React Fragments should be used when the styling / layout of your elements are dependent on their order / nesting

technically correct (but kind of contrived) examples:

okay, but when should i actually use it

whenever you need to get rid of a div

when you need to turn this rendered output:

<div class="app">

    (...a bunch of other elements)

    <div> (my react component)
        <ComponentA></ComponentA>
        <ComponentB></ComponentB>
        <ComponentC></ComponentC>
    </div>
    
    (...a bunch more elements)

</div>

into this rendered output:

<div class="app">

    (...a bunch of other elements)

    <ComponentA></ComponentA>
    <ComponentB></ComponentB>
    <ComponentC></ComponentC>
    
    (...a bunch more elements)

</div>

Example: 2x2 CSS Grid

grid layout:

(brand / top-level nav)

content header
  • subnav menu item 1
  • subnav menu item 2
  • subnav menu item 3
content
.grid {
    display: grid;
    grid-template-areas: 
        'topnav header' 
        'subnav content';
    grid-gap: 1em;
}
  1. items in the left column don't change
  2. items in the right column both change when navigation / state changes

component structure

basically, we want this:

<div className="grid">
    <TopNav />
    <SubNav />
    <ContentComponent />
</div>

to render something like this:

<div class="grid">
    <div class="topnav"  />
    <div class="subnav"  />
    <div class="header"  />
    <div class="content" />
</div>

the problem is:

if our ContentComponent renders an extra div:

class ContentComponent extends Component {
    render() {
        return (
            <div>
                <div className="header"/>
                <div className="content"/>
            </div>
        );
    }
}

it totally screws up our CSS grid.

<div class="grid">
    <div class="topnav"  />
    <div class="subnav"  />
    <div>
        <div class="header"  />
        <div class="content" />
    </div>
</div>

to fix it, use a React Fragment!

<div className="grid">
    <TopNav />
    <SubNav />
    <ContentComponent />
</div>
class ContentComponent extends Component {
    render() {
        return (
            <React.Fragment>
                <div className="header"/>
                <div className="content"/>
            </React.Fragment>
        );
    }
}
<div class="grid">
    <div class="topnav"  />
    <div class="subnav"  />
    <div class="header"  />
    <div class="content" />
</div>

Recap

class ContentComponent extends Component {
    render() {
        return (
            <React.Fragment>
                <div className="header"/>
                <div className="content"/>
            </React.Fragment>
        );
    }
}

Thanks so much!

ken_hoff