React in Anti-Patterns: Partials
React provides us with many great things without enforcing much at all. This leads people to refer to React as an non-opinionated tool, and many people love React for that reason.
React has a very simple API and only requires understanding of a few very simple concepts. React does not make you do much at all. In fact, React even offers backdoors for you to completely disregard the abstractive power of the tool, altogether.
dangerouslySetInnerHTML, use incompatible libraries and bridge the gap with
uncontrolled components, break React’s signature data flow by using
context, and now in React 16 we can control a part of our application from another part of the DOM tree by using
Aside from the ways React allows you to diverge, there are countless ways that you can get away with implementing other anti-patterns in React without React batting an eye.
“Right or wrong, there is not. There is but Foo and Bar.“
Hell, I still do things wrong until they’re brought to my attention (with justification) that they are wrong. And I’ll admit, I suck so bad at Redux that most of my code reviews are just mountains of comments about what I am doing wrong.
This post aims to help other established React developers identify and liberate components from an amazingly convincing and sly, imitative anti-pattern that I’ve observed and studied in 3 enterprise-grade codebases: partials.
But, first, the little made case for what React is and why I stand behind it.
React is not just a UI library.
With such a small API and passive personality that it allows us to do virtually whatever we want, how is React so damn powerful?
React is a philosopher, not an English teacher.
The reason React is so damn powerful is because, if you follow the React way, it teaches you to write more code with your head, rather than with your fingers — and this is exactly what you must focus on when you are building software, be it for the web or not.
React provides us with a powerful way of thinking about how to build client-side applications, as well as a small foundation of code to get us started in the right direction. But the emphasis here is on the thought.
React suggests robust design patterns.
I stand by React because it made me a better developer. Not just in the things I am capable of doing, but in the way I am capable of thinking.
I choose React in my projects not for some foolish justification like “I use the right tool for the job” or “react iz da best & angular suckz!”²
I choose React because I believe in the patterns it suggests, and I believe that correct implementation of such patterns make for insanely powerful software with very few head scratching moments. And I am inclined to assume that if you use React, you choose to use it for the same reasons.
With that said, why would we believe in and stand by patterns, but then implement contradictory patterns in our software? Where is our integrity?
The case against partials.
I have had many a fiery debate about this topic in the past year. Friends, colleagues, random developers on the web, and people from all walks of life want to fight for this anti-pattern.
Why? The answer lies in the developer’s natural instinct to be efficient, keep things simple, and do more with less. I’ll spare you any more of my assumptive psychology.
Here is an example of the partial pattern in React:
Let me go ahead and disclose that I am not passing judgement on you if you are a practitioner of this pattern.
At first glance, this pattern doesn’t seem like a problem. You may have seen it in tutorials and even use it in your own projects. It makes sense in the moment. But before I make my accusations, let’s cover the reasons I usually hear for supporting this pattern.
“It makes my code more readable.”
I disagree. Upon opting to use this pattern, following your data becomes a maze, and you can no longer read your component like a document, top to bottom. You now have to jump all over the damn place to figure out what is going on.
“My render method would be huge if I did it all there.”
The solution to this should not be splicing up your render block, but searching for the missed opportunities you had to break down logic and compute and optimize data before it reached this
“I didn’t want to make another file just for this simple function.”
I would argue that navigating files with a good editor/IDE (or hell, even VIM) is simpler than digging through hundreds or thousands of lines of code in a single file, any day. But that is just my opinion.
Here’s something more objective: If you’ve deemed a piece of render logic intricate enough to be a concern of its own (which a render block is) and live in a function by itself, it is a component, and in React components get separate files. (Unless you’re on CodePen.)
I never receive any objections based on code quality. Only aesthetics and opinion.
Smooth, involuntary criminals.
I am very happy that people are trying to practice modularity. But what is the real result of this pattern?
Essentially, you are creating tiny components, something that React already provides a pattern and API for. But you can’t even call partials “stateless functional components”, because they are not functional in any way, shape, or form, nor are they “stateless.”
How about we cover the various issues with partials in React?
The unit test, at its best.
When you create a new utility function in your codebase, you have to write a unit test for it, right? Unit tests are a pattern that provide a benefit to your development as a whole. Even components get unit tests, most commonly with Jest and Enzyme. (Because after compilation, they’re just functions.)
So why don’t you go ahead and write me a unit test for one of these partials without making each of them a
static method. I’ll wait right here for your solution.
The closes you could get to testing these partials is to test the context in which they live. But that is not a solution. If “unit” testing a scope was acceptable, we’d only need to write a single test for our entire application, rather than for each unit.
When you choose to use partials, you choose a pattern that defies the laws of good code. You create un-testable segments of code.
Partials are components that are forced to exist in a non-testable state. They don’t choose the life of crime, the life of crime chose them.
The slavery pattern.
As humans, we generally do not and should not own other humans, and we do not and should not control other humans. Yeah, we can employ another human, and we can give other humans information, but it is the recipient’s decision how to act on that information.
The same laws apply in React.
React components do not own other components, and that is the bottom line. But if you are not convinced by metaphorical morality, maybe you should consider what you will do with your partials when new features come down the pipeline and, every time, your partials have to grow.
- You write a new class method only to be used in a partial.
- You add a piece of state only to be used in a partial.
- You add some more JSX markup inside of your partial.
- You add code that shouldn’t concern the partial’s owner.
You’ll wind up with 3,000+ LOC components that are unmanageable.
Trust me, they exist. I’ve battled with countless of these behemoths.
Then, when you realize the foley of your ways and suggest to your team or manager that you should refactor your partials into actual components, the verdict may very well be that it could have too many side effects and that, for now, it must stay in the current “working” state.
Don’t worry, we will come back and clean it up later.
— Somebody with good intent.
Tip: Tomorrow never comes. Making an application more featureful and appealing to the customer is always prioritized over making the code more maintainable and more stable.
Even if you did get the thumbs up to refactor, you’re going to find that converting a scope-bound partial into a bona fide component is no easy task.
Furthermore; a codebase rarely provides shelter to only one partial. You’l likely have dozens of dozens that require cleanup. It may be severe enough that you need an actual (re)architecture meeting to precede the task.
Partials are a disease.
So, here we are. We’re birthing impure imitation components into slavery, forcing them to exist in ways that break all the laws, and ignoring the correct implementation of the most fundamental concept of our toolset: the
I dare to say that partials can no longer be considered a productive pattern, unless you define productivity in terms of how fast you can piece code together and how few files you can do it with.
We need a new movement. We need to end the slavery of components, kill off these imitations, and write better code. In the meantime, I leave this message for all of the enslaved components in the git universe:
¹ All of these things can be used properly in React as solutions to uncommon scenarios, but in most cases they are used unnecessarily.
² Although Angular does, in fact, suck.