Keep Non-trivial Logic Out of React Components

Stephen DeBaun
Cranky Old Coder
Published in
5 min readDec 23, 2023

PHP just called from 1996; it wants its programming paradigm back. Hey, look! Those of us in the future have a whole box of tools to keep our code maintainable.

And then burn the book. And then chop your arm off to be safe.

OK. I’m not going to bash PHP. Not because I feel bad but because it’s too easy.

But seriously, if you aren’t a monster, you should really not be putting anything more complex than nothing in your React Components. That may look like a double negative, but exercise your primate brain and grok what I’m putting down. I’ll give you some more details…

Do you want to deal with this for all of the afterlife? No you don’t.

The Hell of Twelve-thousand and Three Rabid Badgers

Here’s what I’m talking about; obviously not real code because I’m not such an idiot that I’m going to copy my clients’ code onto medium. But if you’re reading this, you know who you are. And you are on a list.

const MyTerribleComponent = (whateverProps) => {
const [ someStuff, setSomeStuff ] = useState('garbage')

var data = []
for (var i in whatever) {
const someTerribleOpaqueName = whateverProps.thisKey.some((p) => {
p.myObscurePropertyName ?
whatActuallyIsThis('i dont care') :
whoTheHellKnowsWhatImDoingHereProbablyMutatingSomeGlobalState(
p.whatever,
'12345',
'dont you wish you knew what this did'
)
})
data.push({ some: 'object', why: 'because you hate me', ...whateverProps })
}

return (
<ul>
{data.map((d) => <li>
<span>{d.why}</span>
<button onClick={() => {
const madness = yetAnotherFunction(d.madnessSource)
thisIsProbablyASideEffect(madness, d.some)
HopefullyStaticClass.butWait(d.why, 'theres more')
areYouCryingYet()
</li>}
</ul>
)
}

OK, I tried to write more to give the proper impression, but I started getting the shakes and tears started streaming down my face and I had to stop.

But try to imagine a component like that. Got it? Now try to imagine writing it. Sure. Now realize there is a special reserved spot for you in The Hell of Twelve-thousand and Three Rabid Badgers.

Let the fear sink in.

Seriously though, I have no idea from glancing at your code of what it’s trying to do.

Nevermind all the likely syntax errors in that sample code; medium’s linting and intellisense is trash. And while I’d like to say nevermind the naming, unfortunately it is all too real.

But the real WTF here is that you’re forcing every engineer, including yourself, to make their poor brains do way too much work to understand what the hell drugs you were on when you wrote that code. Goofballs? Whippets? Isn’t that what the kids are doing these days?

Brain context switching is expensive. There is real data on this; not the “im going to take horse tranquilizers to cure my covid” kind of data, but real data. Making a brain shift gears to understand different levels of detail is one of those context switches.

To understand this code I have to dig through imports, figure out what the unholy hell all these function calls are, worry about where state is being mutated, and abuse the “Find all References” and “Go to Definition” abilities of vscode like they were socks and I was a sex-starved incel. Yes, I know that last part of that last analogy was redundant.

And have you even started to think about how to write tests for this? Are you just going to manually test this every time you make a change to any code at all in your codebase, or are you just going to say “screw it, I like troubleshooting shit code at 2am when my company is losing $10,000 an hour over due to downtime.” I mean actually I kind of respect that.

Have you not worked with Other Peoples’ Code that was like this? Did your heart shed tears, or are you a soulless monster like the youth of today with their TikToks and hoverboards? Or can you feel the pain?

Good.

Pain is the Best Teacher — Clark

Don’t worry. Salvation awaits…

this is what the next section will feel like.

Salvation Awaits

For real, it doesn’t involve any hail marys or strings of wooden beads of any kind.

Decouple your damn code. That’s the basic idea here. A bunch of other things, like non-asinine naming, separation of concerns, etc. come into play. But let’s find a safe space right now:

const MyNoTearsComponent = ({products}) => {
const productsWithDisplay = productDisplayAugmentation(products)

return (
<ProductList>
{ productsWithDisplay.map((p) => <ProductListItem {...p}/> }
</ProductList>
}

Ah, OK, I’m calming down now. I know it’s fake code, but that fake code and an extra-crisp bottle of Stella Artois are soothing my troubled soul. I can put on Charles Mingus and dim the lights and sip my Stella and pretend that all is right in the world.

I can read that code and see that there’s no use so I know it’s not dealing with any persistent state. I can tell it has to do with products. I can quickly see that it’s just taking the props it’s being passed, doing some display-related transformation, and passing it on to some child components that are specifically dealing with products.

I know that whatever the hell bug started costing us $10k a minute at 2am in the middle of my annual 24-hour Big Trouble In Little China binge, it’s not here. If I’ve set up my error tracing worth a damn, I’m probably not even looking at this code. I don’t ever need to look at the unit tests to figure out what this does because we were smart enough not to write one because we realized it was pointless.

I mean shit, if we did a better job with our automated e2e testing, I would be at the 5th episode (of identical episodes) right at the point where Lo Pan tells Jack, “YOU WERE NOT PUT UPON THIS EARTH TO GET IT”.

And my troubled soul would be resting easy.

--

--