Does React Have A Cult Problem?

Jack Herrington
4 min readApr 3, 2024

--

As a React content creator I’m often surprised at the reactions to some of the videos I create. I’m often mystified when I talk about anti-patterns and how to avoid them, only to find folks in the comments passionately defending anti-patterns as best practices.

I think this happens because React has a huge user base, and, let’s be honest, it can be a bit of a challenge sometimes to write good React code. So a lot of advice on React can go viral and folks just believe it without thinking too critically about it. Which creates a kind of cult mentality.

Sometimes the original content is good, it just gets boiled down and condensed into nonsense. That’s the case with the “never spreaders”. These are folks who think the spread operator in Javascript is the source of performance problems in React applications. Spoiler Alert: It’s not.

The Never Spreaders

The origin of the “spread is always bad” myth was an article about making Tanstack Table 1000x faster. And the core issue was pretty simple. If you follow a functional programming immutability approach to reduce you might create code that looks like this:

const rowLookup = rows.reduce((o, v) => ({
...o,
[v.id]: [v.value]
}), {});

This code iterates through an array of rows to create a lookup object. This is a simplified version of the anti-pattern in the article.

The central issue is that you are allocating unnecessary temporary objects in a tight loop. With every iteration of the reduce you are creating a new object with the contents of the old object. It’s slow because it’s doing excessive copies that get bigger with each iteration. And it eats up memory and creates a bunch of temporary objects that need to be garbage collected.

Thankfully the fix is super easy.

const rowLookup = rows.reduce((o, v) => {
o[v.id] = v.value;
return o;
}, {});

You just mutate the data in place. No temporary objects are created. You just start, and end, with the object the you set as the initial value in the reducer. Functional programmers might take offense at the blatant mutability on display here (Oh noes!), but you know what, Javascript isn’t a functional programming language so they can bite me.

So notice we removed the spread operator. Ipso facto “removing the spread operator” became the takeaway here. Not that the spread operator used the wrong way was bad, just the spread operator altogether was bad.

When Primeagen covered this on his YouTube channel he made the distinction as well; the issue was the spread operator used in a tight loop. But that subtlety clearly got lost in translation.

It all got simplified to “spread operator bad”. And that immutability, in the large, was bad because it was memory inefficient. The immutability point is a good one to have a debate about, but at the end of the day, React, is based on immutability. Trying take immutability out of React, or completely try to work around it, is going to result in nightmare fueling code.

Simply putting onClick = () => setData({ ...oldData, count: count + 1 }) in your code isn’t going to cause a performance problem. Spread is the right choice in this case. It is the fastest way to create a shallow copy of an object and setData will only work if you give it a new object reference. So spread operator it is!

And honestly, if memory allocation your big concern, then there are far bigger issues with your components than this dinky spread operator that’s only run on a user interaction. Every time you add a tag in your JSX you are actually invoking jsx or createElement under the hood. That call is allocating memory. The properties that you put on the tag, those are bundled into, you guessed it, another temporary object. Those allocations outnumber by… well, by the number of tags in your JSX, which is probably a lot with the <div><div><div> stuff we do.

This Is A Mindset Problem

The “never spreaders” are just one of a bunch of different “cults” I cover in this video.

React’s Cult Problem: The Video

All of these “cults” are symptoms of some mindset problems in the React community. This never spreader idea is an example of absolutist thinking; never do this, always do that. There are very few cases in software that something is always good or always bad. Everything in software is about pros and cons. It’s a game of tradeoffs.

The immutability aspect of React itself is a trade-off. The bet is that there will be less memory allocation, which is slow, and more memory comparison, which is fast. In a mutable variant you would trade off in the opposite direction, mutations would be fast, but comparisons would be slow. Personally I’ll take the React side of that bet.

Most of the time the spread operator is fine, sometimes it’s not, as developers it’s our job to know why it’s bad in certain circumstances and to not use it that way. So my advice to you dear reader is to never stop at just taking someones word for whats good and bad, always dig into the details and understand the root cause. Digging into the details to understand the problem is a critical part of going from a junior developer absolutist mindset to a senior developer pros/cons mindset.

--

--