Metal Toad has been building applications and cloud environments for some of the most well-known global brands for over a decade. Learn more > >

ReactJS Architecture

ReactJS Architecture: Part 3

Review

In Part 2 (http://www.metaltoad.com/blog/yagni-react-architecture-part-2), we discussed configuring Director to listen for route changes and run a route handler (conveniently all Director does (and why I love Director)). In this post, we will finally do some React writing. Not a lot. But some. This series is intended to be about React architecture, not necessarily React code creation (which maybe maybe we’ll do later).

This Post

The point I’d like to get across in this post is why I structure React components the way that I do for this architecture. It pairs nicely with the Director configuration we set up in Part 2, and it allows me to get content up and running quickly. The purpose of this series is more for the purpose of, “I want a thing up and running immediately and don’t want the overhead of a flux framework.” So the overhead of a flux framework, GraphQL/Relay layer, complex webpack configuration, etc. just isn’t worth it (right now). FWIW, an app that I’m working on is using this implementation for its, “Is this a good idea?” phase and, if the answer to that is yes, moving to a more traditional Redux stack will be a necessity.

Containers vs. Components vs. Smart vs. Dumb

Before reading on, I recommend reading Dan Abramov’s post about Presentation vs Container Components (https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#…). I posted this recommendation in Part 2 as well. When I first started React code, I had an almost identical idea (although not nearly as well articulated or functionally correct) that I referred to as Smart vs Dumb components (which Dan brings up in his post). I like the idea a lot, and I think it’s an excellent introduction to React coding. The concepts emerge naturally and the code separation is easy to navigate, as well as easy to jump into.

In short:
•A smart component knows about it state. It can initialize, fetch, and update its own state. It will pass state values to children as props. These are sometimes not reusable.
•A dumb component does not know about state. It receives data and renders it via props. Dumb components should always be reusable, as they are not coupled to an implementation or valueset.

In my code/codebases, I use “Container” and “Component” to reference Smart and Dumb components. Containers contain various amalgamations of components.

An example:

//A component/dumb component
import React from 'react';
import ReactDOM from 'react-dom';

export const ContentSection = React.createClass({
render() {
return (

{this.props.content}

)
}
});

In the above component, there is no need for getInitialState or any logic other than render, as the component is dumb, it is prop driven.

Another example:

//Another dumb component
import React from 'react';
import ReactDOM from 'react-dom';

const Comment = React.createClass({
render() {
return (

)
}
});

Here we have a styled, standardized Comment component that is driven by its parent. This Comment can work with whatever context it lives in, as it is props-driven. Now these have both been very basic examples, but for the most part dumb components should be pretty simple to reason about anyway. They’re dumb. They don’t contain logic or understand why they exist, they just exist. That’s why dumb components are entirely reusable, they fundamentally can’t be coupled to an implementation, as they have no implementation. They really just serve their Containers.

So, Containers.

Containers can be large and complex. Sometimes Containers aren’t reusable, which is (for the most part) fine. Containers can be reused if their implementation exists in multiple contexts. Think of Facebook. You can comment on a friend’s status update via your own feed, or by going directly to their page and viewing the status update there. In both contexts, the comment will be hitting the same API endpoints, solving the same problem, and managing the exact same state (a comment on a status update). Because of this, a Comment Container that knows about its children, knows about API endpoints, knows about its implementation (in this example, a Status Update) can be reused.

Another basic example:

//A container
const SomeContainer = React.createClass({
getInitialState() {
return { comment: '' };
},
change(event) {
this.setState({ comment: event.target.value }, Services.updateCommentService);
},
render() {
return (


)
}
});

This is an extremely basic example that doesn’t really do stateful components justice, but the idea is good. The Comment logic doesn’t need to be muddled with the other Container/Component logic, the Container can know about the service/endpoint that needs to get updated for that specific comment; and adding new components to the Container is super easy and doesn’t interfere with the logic of the rest of the implemented components.

printState

A helper function I wrote has turned out to be extremely useful for me while in development. When a React component calls setState, the state is not updated immediately, so the following code will not work as expected:

change(event) {
this.setState({ comment: event.target.value });
console.log('STATE', this.state);
}

However, setState takes an optional callback as a second argument, which will be executed after the state has been updated. So, the helper function:

function printState() {
console.log('STATE', this.state);
}

This function will run with the state of whatever component it is applied (because of how the this keyword works). So nearly every time I call setState, I pass it in after the state object just to see what’s happening. For complex Containers that have multiple sub-components, it’s a great way to see how your overall state object is mutating. It seems small, but has saved me a lot of time. After all, state management is one of the hardest things to get right during UI development.

HOW DOES THIS YAGNI?!

So this post has been about React code creation (I lied earlier, I guess). Hopefully, when I write Part 4 (tying it all together), if Director + Webpack have been configured as directed (pun intended), the app just falls into place. Next post, we’ll go over how Containers/Components play into the Director + Webpack + React + Superagent configuration, and also probably go over a services layer to interract with the rendering layer.

A fiddle!: https://jsfiddle.net/t8t71fah/

Learn more about JavaScript in our JavaScript Blog Archive.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Ready to get started?