CRUV: Structure React apps in 4 directories and 3 files

So you’re starting a React project. You know what you want to build, and quickly spin up a project with create-react-app. And then you’re confronted with the problem of where.

Where do your components go? Where should you put business logic? Where do higher order components fit in? And even if your structure feels right now, how do you know that it won’t feel wrong later?

If you’ve used other frameworks, you know that it doesn’t have to be this way. Rails gives you structure. So does Angular. What if React also had a system that told you exactly where files go? You could focus on building stuff instead of dicking around with folder structures.

In fact, there is a system that does just this. I’ve been using it for months now. It works great with create-react-app and any router you pick — even no router! And it’s named CRUV, after the 4 directories that you’ll use.

Containers, Routes, Utils, Views

CRUV is inspired by the directory structure from Ruby on Rails. It gives you four standard directories, for the things that you’ll definitely use. Then it lets you add other app-specific folders and subdirectories once you need them.

Creating a CRUV app is simple. All you do is generate an app with create-react-app, and then create 4 folders and 2 files. You can try it out by copying and pasting this into your terminal:

create-react-app myapp
cd myapp/src
mkdir containers routes utils views
touch config.js contexts.js 
mv App.* routes
sed -i '' -e 's/.\/App/.\/routes\/App/g' index.js

See the gist »

But what do the 4 directories and 2 files in this structure actually do? Let me demonstrate with examples from the app that runs my new Raw React course. Shameless plug: join my newsletter at the bottom of this page to keep in the loop when the course is released, and get a massive discount.

CRUV directory structure" width="150" height="150" class="alignnone size-thumbnail wp-image-1201"

/containers

This directory contains reusable container components. These components handle business logic, delegate style/markup to view components, and importantly, are used in more than one place.

Container components can also communicate with the server. In larger apps, they may delegate this to a Redux or Apollo store. But in smaller apps, they’ll usually just call the server directly.

Examples include:

  • An <ArticleContainer /> component that loads and wraps MDX documents.
  • A <CourseLessonContainer /> component that loads course access/progress from the server, and handles user requests to mark lessons as complete.
  • An <EditorContainer /> component that handles loading/saving of the students’s answers for exercises.

But what if you have something that looks like a container, but is only used once? Then it probably goes in /routes.

/routes

Routes are general purpose components that are only used once. They can handle both business logic and presentation internally, or they can delegate it to containers or presentation components.

Routes often correspond to individual URLs, and that’s where they get their name. But routes can also be independent of URL.

Examples include:

  • An <App /> component that wraps everything else, renders the app header, and decides what to render based on the current URL.
  • A <LandingPage /> component that contains your landing page’s content.
  • A <LoginPage /> component that shows a login form, and handles user input on that form.

So what router should your routes use? Whichever router you’d like, or even none at all! Because even if your app runs from a single URL, you’ll still need an <App> component. Maybe you’ll have other one-off components too.

/utils

This is the place to put files that get copied and pasted between many different projects. Things like vanilla JavaScript functions and classes, higher order components, and other utilities.

Some examples include:

  • A formatDate() function that converts JavaScript Date objects into strings.
  • A <Dimensions> component that uses a render prop to make the width and height of its children available.

/views

Put components that render markup and styles here, along with components that receive and display user input. Dan Abramov calls them presentational components. I call them “views”, because it’s faster to type within import statements..

Some examples:

  • Styled <Button> components.
  • A <CourseCard> component that creates a link to a given page, and looks like a “card”.
  • A <Grid> component that is used within route components and other views to handle layout.

I tend to start by creating one .js, .css and .test.js file per component, and putting them directly in the /views directory. So for example, /views/Button.css, /views/Button.js, and /views/Button.test.js. But this isn’t a hard and fast rule; you can also export multiple components from a single file. For example, an Indicators.js file may export both <Spinner /> and <LoadingBar />.

/config.js

Apps often have configuration that differs depending on the environment. For example, an API_KEY environment variable that differs between development, staging and production. While you can access this kind of configuration directly from process.env, I prefer to export it from a top-level config.js file. For example:

export default {
  server: process.env.REACT_APP_SERVER || 'http://localhost:3000',
  publicURL: process.env.PUBLIC_URL,
  stripeKey: process.env.REACT_APP_STRIPE_KEY,
}

/contexts.js

To use React’s Context API, you’ll frequently need to import <Context.Consumer /> components, which often don’t fit in any of the other categories. I like to keep these components in a single top-level file, making them easy to access, and also discouraging over-use of context. Here’s an example:

import * as React from 'react'

// Current route and methods for interacting with browser history
export const NavContext = React.createContext(undefined)

// Data received from server
export const StoreContext = React.createContext(undefined)

// UI context, including whether the subtree is disabled, is a form, etc.
export const UIContext = React.createContext(undefined)

/index.js

This is your application’s entry point, as created by create-react-app! Simple, huh?

As your project grows…

As your project grows, your views and routes folders can start to feel a little full. In this case, you might want to add subdirectories for each component, with an extra index.js file that re-exports the components. This let’s you keep the same filenames as before, without having to change any import statements.

For example, a /views/Button/index.js file might look like this:

export * from './Button.js'

You may also find yourself adding subdirectories that group related components. For example, I have a /views/editor subdirectory that groups together all the components involved in my course’s live editor.

Finally, in addition to the standard four CRUV directories, you may also find other useful directories. For example, my app has a /types directory, because it’s written in TypeScript. But I didn’t start with this directory. I only added it once my /utils directory got a little heavy with type definitions.

The reason that the CRUV structure works is that it’s just a starting point. When you’re just starting out, it gives you a simple structure to work with so that you can concentrate on writing actual code. And once your folders get full, all you need to do is find a few similar files, and move them into a new directory. It’s easier to categories files that already exist than to predict the future.

But where do my reducers go?

You may noticed that I haven’t added a directory for Redux reducers. And that brings me to this article by one of the creators of Redux: You Might Not Need Redux. Yes, you read that correctly: one of the creators of Redux is asking you to reconsider using Redux.

The reason that there are no /reducers or /actions directories in the CRUV structure is that Redux is optional. In fact, I write apps without Redux all the time!

But what if you do use Redux? Or MobX? Or Govern? In that case, my recommendation is that you add a /store directory, and put all your store related code in there. Stores hold global state that isn’t tied to a specific component, so they generally shouldn’t be very large.

And if you do have state that needs to be tied to a specific component? Use setState()! That’s what it is there for; component state is a simple, powerful, and underappreciated tool. Raw React can get you a long way.

Where is CRUV used?

If you’ve worked with some React apps before, CRUV may feel familiar. While the names are probably a little different, this pattern is something that often evolves by itself — especially when building on the Presentational and Container Components pattern.

In my case, CRUV is the structure that evolved from an app that I’m building to teach Raw React. I’ll be going into more details on how I built the platform behind the course soon. To get the details, or to be the first to hear about the Raw React course (and get a massive discount), join my newsletter below! I’ll even email you five free PDF cheatsheets to sweeten the deal.

I will send you useful articles, cheatsheets and code.

I won't send you useless inbox filler. No spam, ever.
Unsubscribe at any time.

One more thing – I love hearing your questions, offers and opinions. If you have something to say, leave a comment or send me an e-mail at james@jamesknelson.com. I’m looking forward to hearing from you!

JSX, HTML-in-JS and CSS-in-JS

Lately, I’ve been hearing a lot of people talk about JSX as if it is HTML-in-JS. So let me clear something up:

JSX is not HTML-in-JS.

The thing about JSX is that it is just a special syntax for writing plain-old JavaScript.

Each JSX element compiles to a call to a JavaScript function called React.createElement. In fact, you can write apps without using JSX at all; just call React.createElement by itself. Like this:

ReactDOM.render(
  React.createElement('div', {}, "Hello, world!"),
  document.getElementById('app')
)

To repeat myself, JSX is not HTML-in-JS. Yes, it is a way to specify the structure of the DOM. But so is raw JavaScript, like this:

const app = document.getElementById('app')
const hello = document.createElement('div')
hello.appendChild(document.createTextNode('Hello, world!'))
app.appendChild(hello)

If you’re writing an app with JavaScript, you need some way to modify the DOM. JSX is one way of doing it. Raw JavaScript is another. But in either case, you’re still working with JavaScript.

In contrast, HTML-in-JS would look a little like this:

const hello = "<div>Hello, world!</div>"
document.getElementById('app').innerHTML = hello

And sure, this is something you can do. Just like you could chug a bottle of Tabasco. A friend did that once. He was weird. But I digress.

Want to learn more about fundamentals like React.createElement? My Learn React By Itself series was made just for you!

CSS-in-JS

Another thing a lot of people are talking about lately is CSS-in-JS.

Unfortunately, CSS-in-JS is actually exactly what it sounds like. It is literally CSS in a JavaScript file. Let me repeat that. It is actually CSS in a JavaScript file.

The thing is, there are a number of very good reasons we generally put CSS in CSS files (or their LESS/SCSS cousins). For example:

  • Browsers expect to load CSS from CSS files.
  • Editors have syntax highlighting based on file extension.
  • Tooling such as minifiers and linters expect CSS.
  • Existing CSS libraries are written in CSS, LESS or SCSS.
  • CSS files can be cached separately from JS files.

Some CSS-in-JS tools do lots of very clever things to provide workarounds for all of these issues. But if you just use CSS or LESS or SCSS, you don’t need to provide workarounds. It just works.

Of course, there are supposedly a number of benefits. But most of these benefits can be had from more mature tooling like LESS, SCSS, CSS Modules and Webpack (which you’ll need anyway to, you know, put your CSS back into CSS files).

There are some benefits that are unique to CSS-in-JS:

  • You can add things like media queries directly to components, whilst you can’t with standard inline styles. (Yay?)
  • You can share JavaScript variables with stylesheets. Except that this is is massive security hazard.

But all the big names are using it, so it has to be good, right?

So here’s the thing: CSS isn’t perfect. It makes sense that smart people are building alternatives. And the tools do have some compelling use cases — they’ll work with react-native, for instance. But unless you 100% know what you’re getting into, and 100% understand the security implications, I’d wait a little bit longer before jumping on any bandwagons.

I’ve put a few more details on React Armory in my answer to Should I use CSS-in-JS?.

More good news

Keeping up with JavaScript and React can be exhausting — but it doesn’t have to be! The secret is that the basics never change. In fact, my most popular articles are ones I wrote years ago, and they’re still as relevant as ever.

JavaScript fatigue happens, but you can avoid it by sticking to the basics. And that’s why my fortnightly newsletter just focuses on the JavaScript and React fundamentals. So subscribe now — and get a bunch of free PDF cheatsheets as a bonus.

I will send you useful articles, cheatsheets and code.

I won't send you useless inbox filler. No spam, ever.
Unsubscribe at any time.

One more thing – I love hearing your questions, offers and opinions. If you have something to say, leave a comment or send me an e-mail at james@jamesknelson.com. I’m looking forward to hearing from you!

Read more at React Armory

Introducing MDXC: A new way to write Markdown for React

Read the README and browse the source on GitHub, or mess around with the live demo.

Markdown is a fantastic tool. It makes writing simple. Markdown documents are plain text, so you don’t need to worry about tags and HTML and all that. You just write. And when you need a <a>, or a <h1>, it’s already there. It’s like magic!

But say you’re writing a React app with pushState, and you don’t want your links to use <a> tags; they break your smooth navigation. You want them to use react-router or react-junctions’ <Link> tags instead. And you’re shit outta luck, because you can’t. Or you couldn’t, before MDXC.

MDXC is a tool to make Markdown and React best buddies. Unlike traditional Markdown, MDXC produces actual JavaScript — not strings of HTML. MDXC lets you embed raw JSX within your Markdown, and even lets you import components and accept props. And to top it all off, MDXC lets you configure how each element is rendered, giving you all sorts of ways to confuse your users and also a few ways to genuinely improve their experience.

If you can’t tell yet, I’m pretty excited about MDXC. So please indulge me and take a gander at this example:

Continue reading

Why I created junctions.js

TL;DR? Junctions is a new, composable alternative to react-router. Get it at the junctions.js website!

It was pretty normal day in Tokyo when I received a request from a client. “I’d like this application screen to be a React Component. And I want it to be reusable.”

Given my client’s app was created with React, I naturally said “Yes Sir”. I mean, the best part about React is that components are reusable. What could go wrong?

Continue reading

Do I Even Need A Routing Library?

So you’ve decided to build a React app. It has a few screens, so you need a router. And react-router seems pretty popular, so you npm install it and put together a quick demo. Everything seems fine and dandy!

Or it did, until you googled for some docs the next day. Something seems off. The logo has changed colour from blue to red. And the version number has mysteriously increased from 2 to 4. Huh?

Well at least it didn’t jump to 5. But this makes you think — do I really even need a routing library? Imagine if we lived in a world without JavaScript fatigue where the APIs never change and we could just focus on making awesome stuff. But actually – we kind of do! The browser APIs rarely change. And how much longer could it take to just use them instead of some complicated library?

Continue reading

Why use parenthesis on JavaScript return statements?

A while back, I received a great question from a reader:

Just a note in your Learn React By Itself tutorial. In the “Components” section, where you say:

return (
  React.createElement('li', {className: 'Contact'},
    React.createElement('h2', {className: 'Contact-name'}, this.props.name)
  )
)

It’s not clear to me why you need the parens and can’t just do return React.createElement. I tried that and it fails but I can’t see why. Isn’t typeof x === typeof (x) in JavaScript?

And while it is true that typeof x === typeof (x), the same doesn’t always hold for return. Why?

Continue reading

State of React #2 – From Inception to Redux

Welcome back to the second instalment of State of React! In case you missed it, the first instalment demonstrated a small app without component state. And it received a bunch of interesting responses, like this one from @metapgmr:

using props as state and claiming that components are … stateless! The React Emperor has no clothes

Yes, the app was basically wearing its birthday suit. And yes, the app did contain state. But no, the state wasn’t in the props – and it wasn’t component state either.

So what was it?

Continue reading

State of React #1: A Stateless React App?

Have you ever been frustrated with the task of making loading spinners appear at the right time? Or maybe you’ve had trouble making a popup appear when and where you want it? These are both signs that your code suffers from unmanaged state — the bane of basically every web developer on the planet.

And luckily, the React ecosystem is brimming with tools to help. Redux, MobX, Flux and RxJS are just a few. And while they have a number of things in common (including for some reason the letter “x”), the one which stands out the most is that they just convert the problem of “managing” state into the problem of “structuring it”.

But if it seems that there is no way to dull the state of pain, it begs the question — instead of managing our state, why don’t we just avoid it?

Continue reading

Announcing ReactJS Tokyo

Have you ever wondered how other people write React apps? There are often multiple ways to solve the same problem, but finding the best way doesn’t have to mean implementing each of them yourself!

So what I’m trying to say is that if you don’t like learning things the hard way and you’re in Tokyo, you should totally come along to the first ever ReactJS Tokyo meetup.

All skill levels of English, 日本語 and JavaScript are welcome. Snacks and drinks will be provided. It will take place on Thursday, 28th July in Roppongi, and places are limited. So make sure to register early.

Look forward to seeing you there!

Should I use shouldComponentUpdate?

So you heard React was fast, and decided to give it a go. You grabbed a boilerplate, started working through it, and noticed shouldComponentUpdate and PureRenderMixin. Some googling reveals these are the things you use to make React fast. But wasn’t React already fast?

The answer is that React is fast… sometimes. The other times, you should use shouldComponentUpdate. But when are the other times? Wouldn’t it be so much easier if there was just a simple yes-no question which you could ask to decide whether to use shouldComponentUpdate or not? And wouldn’t you believe it, there is!

Continue reading