One month with React

This is part three in Bytesized’s A year with React.js series, which explores increasingly complex aspects of being a React developer. This post covers your first month with React––application structures and open-source libraries. It’s strongly recommended that readers start this series from the beginning, with the first post, “One hour with React”.

In the previous post in this series, we explored React components that render other components. In doing so, we begin to come up against the question: what does a well-crafted React application look like?

Exploring the concept of “good” code is a topic for another time, but most programmers know bad code when they see it. If they can’t sense it immediately, they will as they begin to work on it; that feeling of helplessness, where it’s unclear where to even begin with a new feature, or how to fix something that isn’t working. In this post, we’ll explore a single facet of good code–the concept of structure.

Well-structured code gives developers a vantage point into an application. With a well-structured application, it is clearer where a new feature should be built. It is more clear how an old feature is failing. A good structure, in short, lends itself to maintenance, not creation. The seminal programming book Clean Code has this to say on maintenance:

…in the auto industry, the bulk of the work lies not in manufacturing but in maintenance—or its avoidance. In software, 80% or more of what we do is quaintly called “maintenance”: the act of repair. Rather than embracing the typical Western focus on producing good software, we should be thinking more like home repairmen in the building industry, or auto mechanics in the automotive field.

If you’ve ever worked on a software project for more than a couple years, you’re likely intimately aware of the phenomenon of encountering your own code, and not understanding it. If it isn’t your own code, and it’s a departed team member, the situation can be even worse: it still doesn’t make sense, and the person who wrote it isn’t around to answer questions! Maintainable code becomes a prime concern after a short amount of time in an application, and this is no different with React applications.

Application structures

React is often referred to as simply “the view layer”. Most applications, whether web or anywhere else, follow a similar implementation pattern. There is code to produce data, to load it, to display it; the Model-View-Controller (MVC) pattern is common among many programming languages. Regardless of how it’s implemented, there is often a point in a software project where you have data that needs to be shown to a user.

Other web frameworks differ in complexity from React; Ember, for instance, provides the entire spectrum of tools needed for a web application. Version 1.0 included not just Handlebars templating for the view layer, but powerful controller and model tooling. The same story has applied to many web frameworks: it’s very easy to think of a web framework as incomplete if it doesn’t handle the entire end-to-end process of retrieving and displaying data.

React takes a different approach by firmly providing just views. Data can be passed in, sure, but React provides no built-in tooling for manipulating or loading data, besides what JavaScript itself contains. Want to load data? Check out Facebook’s GraphQL library, which has rethought the concept of retrieving data via REST. If your data is already defined and available, the popular Redux library can store your data and inject it into your React components.

(Be sure to check out our new Redux introduction series, too! Redux manufacturing)

I’ve referred to React’s ability to change how you write and think about code in every post in this series. React is a wonderful tool because it is obsessively simple. In being simple, it forces you to make changes to how you structure and reason about your application, and about the data that it needs. Redux is similar: data flows a single direction, so the way that you think about how data should move in your application will be permanently changed. In both these situations, is this the end-all, be-all, perfect solution to building applications? It’s hard to say–it does, however, paint an incredibly compelling and straightforward path to take in the future.

React components are functional by design–given input, we can always expect the same output from our render function:

output = render(input)

This line of code almost looks like an equation. Building out React component trees, like we did in the previous post in this series, is like combining many render equations into a single application:

header = render(title) + render(menu)

post = render(post_title) + render(post_date)
content = render(post) + render(post)

application = header + content

In building applications, React becomes somewhat of a game, as we explored with component trees: how modularized can we make this project? At what point does the application stop looking like a bundle of HTML, and more like a collection of highly-independent components?

Consider React Native, Facebook’s project to bring React to mobile devices. There are a number of stories of successful React Native launches targeting iOS and Android: most notably, Facebook’s own Ad Manager re-used 85% of component code between platforms. That insane level of re-use happens when we try and build maintainable, re-usable code; by building component trees that are highly modularized.

Structuring your React application can be as simple as a single flat directory of components. Our blog component tree from the last example might serve as a good reference:

Blog
  Header
    MenuItem
      Link
    MenuItem
      Link
  Posts
    Post
      PostDate
        SmallHeaderText
      PostTitle
        HeaderText
          Link
      PostContent
        Paragraph
          Link
        Paragraph
  Sidebar
    SmallHeader
      List
        Link
        Link
    SmallHeader
      List
        Link
  Footer
    Paragraph
      Link
    Paragraph
      Link

While there seem to be a number of highly-nested components in this structure, we can begin to see a more reasonable structure by flattening and removing duplicates:

Components/
  Blog.js
  Footer.js
  Header.js
  HeaderText.js
  Link.js
  List.js
  MenuItem.js
  Paragraph.js
  Post.js
  PostContent.js
  PostDate.js
  Posts.js
  PostTitle.js
  Sidebar.js
  SmallHeader.js
  SmallHeaderText.js

This list of components not only provides what we need for our blog application, but it can also provide components for other applications as well. I’ve seen many examples of multiple React applications re-using the same internal components–this provides consistency and rigor around how different teams or different projects are maintained by a larger organization. For instance, we might pull out the more general components not specific to the blog application, and package them as an internal “styleguide” for a company:

CompanyStyleguide/
  Components/
    Header.js
    HeaderText.js
    Link.js
    List.js
    Paragraph.js
    SmallHeader.js
    SmallHeaderText.js

In building this internal package, we could even begin to include more complex components, like Header, and extend or build off of them with custom solutions or by providing the ability to pass in options:

class BlogHeader extends React.Component {
  render() {
    return (
      // Component included from CompanyStyleguide package
      <Header backgroundColor="ffffff">
        <HeaderText color="000000" text="My Application" />
      </Header>
    )
  }
}

This is only scratching the surface of application structure in your projects. Again, we’re striving for maintainable, re-usable code: because React components are functional and straightforward, they lend themselves towards building these kind of modularized projects.

Open-source libraries

But what does this look like in practice, in a real React application? To explore this, we can turn to the wonderful world of open-source. There are a massive number of open-source components for React out in the world, and some of the most popular ones will exemplify good design by nature of being in use by huge numbers of developers and applications.

Some of the most popular open-source React projects repurpose existing design frameworks as React components. The material-ui project is one of these: with over twenty five thousand GitHub stars at time of writing, it’s clear that it’s an incredibly popular project in use by many applications.

Structurally, it looks like you might expect. A src folder designates the location of components, and each component is laid out in its own directory with optional tests (a topic we’ll cover in the next post):

material-ui/
  src/
    Checkbox/
      Checkbox.js
      Checkbox.spec.js
      index.js

The Checkbox component itself is fairly straightforward, with the exception of the number of options that can be passed in via props. Positions, styles, and behaviors are all customizable, and the component’s propTypes definition, a topic we covered in the previous post, is a good introduction into how you might override some of the component’s default behavior.

Interestingly enough, the Checkbox component’s render function reveals that the component does not return plain HTML. Like the best React projects, material-ui abstracts and modularizes the component, using the subcomponent EnhancedSwitch:

class Checkbox extends React.Component {
  render() {
    return (
      <EnhancedSwitch
        {...other}
        {...enhancedSwitchProps}
      />
    )
  }
}

The EnhancedSwitch component is stored in an internal directory, which handles the actual HTML rendering of components. In the render method of the EnhancedSwitch component, a collection of inputs, labels, and event handlers are collated into a single wrapped div:

class EnhancedSwitch extends React.Component {
  render() {
    return (
      <div ref="root" className={className} style={prepareStyles(Object.assign(styles.root, style))}>
        <EventListener
          target="window"
          onKeyDown={this.handleKeyDown}
          onKeyUp={this.handleKeyUp}
        />
        {inputElement}
        {elementsInOrder}
      </div>
    )
  }
}

We can see that in popular, highly-used React projects like material-ui, this modularized method of development highly lends itself to abstraction. It’s a practice that might seem unnecessarily verbose at first, but as projects grow in scale, it will continue to pay off dividends.

material-ui is just one of many incredibly useful React open-source libraries. The following are a couple of wonderful projects, that I can vouch for personally saving me time and frustration in my React applications. You should check them out not only to save you from duplicating functionality that has been battle tested by other users, but also to see what highly functional React components look like out in the world.

  • react-select: this project takes some of the best features of powerful JS select libraries and modernizes them as a powerful React component. I’ve used this library in almost every React application I’ve built–the onChange handler behavior and built-in support for multiselect, searching, and async tooling make react-select a first-class solution worth dropping into any project.
  • redux-form: well-behaved forms are deceptively hard to implement in React. While HTML5 has introduced a number of great behaviors for inputs, from requirement (this field must be filled out) to “type-checking” (this field can only be a number), support is browser-specific and may need to be more complex. redux-form does all of this and more, allowing form data to be passed through and handled by redux and wrapping form submission behavior in smarter, safer tooling. redux-form has a bit of a learning curve, but it has the ability to handle almost any form situation you throw at it. I’ve built a number of complex forms with redux-form, and found that even the basic functionality is so much better than the simple implementation I would have tried to ship an application with–it’s worth taking a look at, even just to consider what things you might have forgotten to include in your form code.
  • react-dnd: I wish that this stood for Dungeons and Dragons, but drag-and-drop functionality is cool too. Drag-and-drop is an interesting example of a JS feature that can break how you reason about your code: it’s so platform-specific and is firmly in the territory of jQuery and DOM-based libraries that including it into a React application can make components do a lot more than they really should. As a rule of thumb, when you begin to put jQuery functions in a componentDidMount hook, you should explore new approaches to that problem. react-dnd handles this as most advanced React components do: your original component becomes wrapped in a “higher-order component”: a component that returns another component. This familiar pattern often takes the form of a specific library function that returns your wrapped component–in react-dnd, this looks like connectDragSource(<YourComponent />). react-dnd is a glimpse at how interactive JS applications can still be written in a functional, performant way, without scattering jQuery handlers haphazardly through your application.

Programmers famously are lazy. We often say “Don’t Repeat Yourself”, and that code duplication is a “code smell”, and a sign of danger. This ethos has been only bolstered by the availability of high-quality open-source libraries.

You might be a really confident programmer and decide that writing your own datepicker component is a good usage of your time. As you begin to test it in different browsers (you are doing that, right?) you’ll quickly find that the CSS solution you had in mind probably doesn’t scale. Have you checked it out on mobile? Uh oh. These kind of concerns are handled when you use a project like react-dates: battle-tested not just by Airbnb, but developed with over fifty contributors coming from a variety of backgrounds and applications.

Want to receive this course in your email inbox? Join the A year with React.js mailing list–it’s instant and easy.

Bytesized offers technical training for companies. Contact us to schedule React.js training for your team today.

Leave a Reply

Your email address will not be published. Required fields are marked *