A big problem with this approach is that as we add components, our src folder will start to fill up fast. There will be lots and lots of files, making it hard to find what you’re looking for. But to me the issue is that we are using a namespaced file structure. Guess what? That’s exactly the problem that folders solve.

Introducing the component folder pattern

What can we do to logically structure all of these files? What if we placed our related files together into a single GiphySearch folder? This is what we do for traditional web development with an index.html and its supporting files. It would look like this.

Nice, but what is that index.js file doing here and what does it do? Well notice that our GiphySearch.js file is now gone. We simply renamed it index.js.

The thing I like about this approach is that once you get your GiphySearch component working, collapse the folder. You’ll no longer be staring at all of those files, reducing visual clutter. Researchers at Princeton University Neuroscience Institute conducted a study that suggests reducing clutter can help you stay focused.

src/|- App.js|- GiphySearch/

Ahh… much better. Looks a lot like the file structure that we started out with, doesn’t it?

Some of you are asking, “Will I have to change my import statements with this new file structure? After all, the code for Giphy Search is inside of a folder and in a file with a different name.” The answer is… NO! That’s the beauty of the component folder pattern.

Your app still looks something like this, no matter if the module lives in GiphySearch.js or GiphySearch/index.js. Hurray for science!

import GiphySearch from './GiphySearch';

const App = () => ( <GiphySearch initialQuery="dog"/>);

Before we dive in and look at the code line-by-line, here is what our new Giphy search looks like.

The after version, using the injected SpinLoad. Try it out and see the code on CodeSandbox.io

Breaking it down

Let’s look at our completed GiphySearch component and what is inside of each file. We’ll start with index.js. It’s sole reason for existence is to maintain state. Nothing else.

Both props, state, and an onLoad callback, are passed down to the View component. How we get the data is handled by the loadData module. This is because neither have anything to do with state.

In fact, look closely. Nothing about this component has anything to do with a Giphy search. It is abstract in about every way possible. Something you could use over and over again. IMO, this is simplistic elegance.

“A component should do one thing, and do it well”

Next is the View component. It will determine what to render. It’s really more of a view controller, as it passes along to other render components to do the actual rendering ﹣all based on state passed in as props from index.js.

import SearchInput from './SearchInput';import Image from './Image';import Loading from './Loading';import Error from './Error';

Notice that we use component injection to render based on loading, error, and data conditions (RenderLoading, RenderError, and RenderImage respectively). Defaults are provided if none are specified.

Next is the loadGiphy file. It uses fetch to hit the Giphy REST endpoint, converts the JSON to an object, and extracts the image URL. It’s rather standard, so I won’t show it here.

The rest of our render components, Loading, Error, and Image are simple stateless functional components, so I won’t waste column inches on them either. However, the complete source code (as well as a live running example) can be found on CodeSandbox.

Reference implementation pattern

There’s one more technique that I’d like to point out. Whenever you use a render callback to perform your rendering﹣whether that be a Function as Child (don’t you dare!), Function as Prop (aka render prop), or component injection (what I use almost exclusively)﹣it can sometimes be advantageous to provide a default if none is specified. I refer to this as the reference implementation pattern.

This allows the consumer of your component to optionally pass in a render component. However, if they don’t, some sort of default or “reference” component will perform the rendering.

Let’s override the Loading component and make it look a bit nicer than the default reference implementation by passing the RenderLoading prop.

While the reference implementation pattern may not always make sense in your component, it’s a powerful pattern to be aware of. This can aid with testing of your component, as you can inject a test implementation.

Conclusion

I hope you get the opportunity to take the disciplines and patterns that you’ve read about here today and apply them to your own code. The component folder pattern un-clutters your project, while the reference implementation pattern allows you to provide reasonable defaults to render callbacks. Both are my faithful companions when writing React applications.

You can read more of my React based articles (including some on Hooks in React 16.7, {…❤️} Spread Love, and React Best Practices) on the AmericanExpress.io Technology Blog.

Update

It was pointed out that using the component folder pattern could make it so that tabs in your editor look like this.

Notice the unfortunate side effect where a lot of tabs are named index.js. Fortunately, Joshua Comeau has a solution ﹣ if you’re using Atom anyway. He’s written a plug-in called nice-index that shows the name of the folder instead.

“We shouldn’t have to change the way we code to accommodate our tools. Get better tools.”

So now when you have multiple index tabs open, you can tell which one is which. I have it installed now and can’t believe that I’ve lived without it for so long.