Getstream. IO/blog/react -…

Hi, my name is Ken and I’m currently working at GetStream. IO, which provides customizable feed streams for users.

Over the past few months, I’ve been working on Winds 2.0, an open source RSS reader and blog subscription application. Developed with Node.js, Electron, Redux and React, and as of July 11, 2018, it already has more than 5000 stars on Github. If you’d like to see the whole project, visit getstream. IO /winds/, or check out github.com/GetStream/w… On the source code.

In Winds, we need React Fragments for certain situations. React Fragments is a neat little feature released late last year with React V16.2.0 — it’s really small, but once you know it, you can avoid a lot of trouble when dealing with very specific layout and style situations.

Okay, what is a React Fragment?

Let’s recap a bit – I’m sure every React developer has faced this situation (or will soon) at some point in their career:

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

It looks pretty good, but when we run it through a JSX converter……

  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>
Copy the code

JSX converters don’t like this 🙁

What’s going on behind the scenes? JSX calls all

s and

s in react.createElement () — when the JSX converter sees multiple elements instead of a single one, it doesn’t know which tag to render. More: React. CreateElement in the React documentation.

So what do we do? We do this every time we need to wrap several elements together — Pinky, wrap them in a div! As Web developers have done since divs were invented, it doesn’t hurt to nest another div in the DOM.

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

Well, the problem was solved. But it turns out there’s another way to render this set of contents in a React component — by having the Render method return an array of nodes.

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

If we return such an array of elements, React will convert and render it without wrapper

. Look neat!

(Remember how the JSX converter converted

and

and was called by react.createElement ()? In this case, the converter simply appends these elements in an array directly to the parent element as child elements, rather than as an array containing no parent elements. React V16.0.0 introduced this feature.

And because of that, Dan Abramov and some of the smart people on the React team looked at it and said,

“Okay, so you can render an array of elements in two different ways – by introducing an extra

in the DOM, or by using some clunky non-JSX syntax. None of that makes for a great programming experience.”

So, in V16.2.0, React Fragments are released

okay,nowWhat ‘s a React fragments?

This is the correct way to use React Fragments:

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

Look – we’re writing just like wrapper

but functionally the same way as array rendering but with nice looking JSX syntax. This renders these P elements as arrays, without any type of Wrapper

.

There is another, more concise syntax for using React Fragments:

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

It might not work with your tools, Linters, build flows, whatever. However, the release notes say that support for this syntax is already in development, but I notice that it is not yet supported in create-React-app.

Okay, but when can I use them?

Before you need to get rid ofwrapper<div>From time to time.

That’s it – use React Fragment if you find yourself in a situation where a Wrapper

messes up your React component layout.

So, that’s when you want to convert this:

<div class="app"> (... a bunch of other elements) <div> (my react component) <ComponentA></ComponentA> <ComponentB></ComponentB> <ComponentC></ComponentC> </div> (... a bunch more elements) </div>Copy the code

To this:

<div class="app"> (... a bunch of other elements) <ComponentA></ComponentA> <ComponentB></ComponentB> <ComponentC></ComponentC> (... a bunch more elements) </div>Copy the code

Example: 2 x 2 CSS grid

In Winds 2.0, we make extensive use of the CSS Grid layout that is common on blogs and RSS feeds.

.grid {
    display: grid;
    grid-template-areas: 
        'topnav header' 
        'subnav content';
    grid-gap: 1em;
}
Copy the code

Okay, let’s explain:

  • In the upper left corner, we have the flag or top navigation bit.
  • In the lower left corner, there are sub-navigations that respond to changes in global and local states, such as “highlighted” states, tabs, or collapsed navigation.
  • On the right, you have something that needs to be displayed on the screen, in Winds, sort of like an RSS feed or article title paired with a list of articles or article content. These two parts will be a single React component – items for both components will change based on the URL navigation.

All of these interactions on global components (REdux + URL) and local state are slightly different. This view is structured so that we have three React components that are brothers to each other:

<div className="grid">
    <TopNav />
    <SubNav />
    <ContentComponent />
</div>
Copy the code

However, we want to actually render the page with four elements:

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

This…… There is no React Fragments problem. Imagine that we are creating two right-side components of a 2×2 grid view, the ContentComponent:

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

If we wrap the rendered content in

, we get the following render output:
<div class="grid">
    <div class="topnav"  />
    <div class="subnav"  />
    <div>
        <div class="header"  />
        <div class="content" />
    </div>
</div>
Copy the code

This doesn’t work – it also messes up the GRID layout of the CSS. From the browser’s perspective, there are only three projects in the grid, and one of them doesn’t have grid-Area styling yet.

Remember how we should use React Fragments? Whenever we want to get rid of wrapper

. If we wrap the ContentComponent in a React fragment instead of wrapper

:

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

Then we’ll see another render output:

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

That’s what we expected! Without wrapper

, our 4 elements are rendered from 3 React components, the browser sees that all elements have the correct grid area style, and our CSS grid is rendered correctly.

Very neat! Now what?

React Fragments are not the most important feature released in recent React releases, but they can be very useful in certain situations. Just knowing that React Fragments exist can save you hours of Google-induced headaches. This allows us to render an array of elements or components in JSX-Y fashion, which solves a lot of table, list, and CSSgrid layout and styling problems!