No One Ever Got Fired for Choosing React
If you spend a lot of time on Hacker News, it’s easy to get taken by the allure of building a web app without a framework. There are a bunch of potential advantages (no bloat! bespoke to your project!) and being able to say you built something with minimal dependencies gets you Engineer Points.
That is, if you can pull it off.
I started a new side project recently. It’s a web-based graphics editor, so it needs to be a single page app. My time spent profiling SongRender for performance issues has made me a little wary of React for building interfaces that update at 60 frames per second, so I decided to avoid it. I’d go (mostly) vanilla and see how far that took me.
I installed lit-html and got to work. “Components” were simply functions that returned lit-html template results. A big singleton at the top of the tree held onto all the application state, stored as a global variable within that module.
The first hurdle came when a component needed local state. I could have lifted it to the singleton, but that would have broken the component’s encapsulation. I noticed that lit-html directives can keep state, so I decided to use them to build a tiny component library — ignoring a warning from the lit-html developers that this wasn’t a supported use case.
My home-brewed library worked great… until I needed to run some code when a component appeared on the screen. I started digging through lit-html documentation and issues looking for a way to detect a directive’s lifecycle, but it became clear to me that going down that path would be painful.
At that point, I recalled this quote by Tom Dale:
I have heard from many developers who have told me that they accepted the argument that vanilla JavaScript or microlibraries would let them write leaner, meaner, faster apps. After a year or two, however, what they found themselves with was a slower, bigger, less documented and unmaintained in-house framework with no community. As apps grow, you tend to need the abstractions that a framework offers. Either you or the community write the code.
Fair enough. Let’s avoid that trap. What about a small framework? I’d heard a lot of good things about Svelte, and although I was slightly worried about the size of the Svelte community I figured it would be fine.
My migration attempt quickly ground to a halt when I wanted a parent component to apply some styles to a child component. In React, I’d pass a class name in from the parent as a className
prop. In Svelte, that’s considered a workaround, and the actual feature is the subject of an RFC.1
Maybe this is an example of dangling by a trivial feature. But it’s so basic a capability that I’m surprised Svelte is on version three without an officially blessed way to do it. I ran into this limitation when I created my second component. Way before I got to try out any of the cool reactivity that earns Svelte all that buzz.
So I changed my mind and went with React. After an hour or so, I’d finished moving everything over — and my anxiety had vanished. I stopped worrying about having most efficient component system, and picked up work on the thing I wanted to build in the first place.
No, React isn’t perfect. It’s optimized for apps that make network requests and then display lists of things (i.e. most apps) which isn’t really what I’m doing here2. The performance is fine now, although I expect I’ll have to optimize as my project gets more complex.
But React lets me stop thinking about the framework. React gets out of my way. React is boring. React is actively developed. React has a giant ecosystem and a giant community. React is battle-tested on some of the most visited websites in the world.
I’m sure there are technically better ways to build a highly interactive interface on the web, but life is too short for me to spend hours trying to figure them out. There are things I want to create, and the only way I can actually create them is to stop spending so much time on tooling.
For now, I’m choosing React.