React Alternatives in 2022

React was a paradigm shift from earlier, more imperative approaches to building user interfaces. Think MVC, its younger cousin MVVM, and all of the myriad approaches to putting together a browser user interface (UI). React simplified the mental model developers needed to keep in their heads to get features on the screen. From 10,000 feet, a component is just a function mapping data to DOM elements. React steps in and makes sure to rerun that function any time the data being passed in changes, and promises to update the DOM to reflect the difference. This frees the developer from tediously mutating the state of the world. Instead, it lets them think in a much more functional and declarative style.

Under the hood, React uses a virtual DOM to separate the developer from the concerns of updating the DOM itself. Basically, when React calls a component’s render function, that function returns a JSON object representing what should be on the screen. Calling render again when some data changes produces a different tree. React walks the old and new trees, builds up a list of differences, and then flushes those differences out to the screen by calling DOM API methods.

Over time, however, some developers have realized that the virtual DOM adds overhead to the problem space that isn’t strictly necessary. Developers have gotten more used to declarative, component-based UI development. So, they’ve looked to other libraries that provide a similar mental model to React’s without the runtime overhead of a virtual DOM. For the most part, these new React alternatives add a build time compilation and static analysis phase that lowers the runtime overhead of the declarative UI paradigm.

So what are some React alternatives in 2022?

Svelte

Svelte was initially released in 2016. It’s a front-end compiler that uses several tricks of Javascript and Typescript syntax to generate vanilla Javascript. The major selling point is that developers can write plain Javascript or Typescript along with plain HTML and CSS. Svelte handles scoping styles for each component so that changes to one don’t affect other components.

A basic counter looks like this:

<script>
  let count = 0;
  function handleClick() {
    count += 1;
  }
</script>

<button>
  clicks: {count}
</button>

The Svelte compiler steps in and generates the necessary vanilla Javascript so that when you click the button, the updated string contents get rendered to the screen. For the most part, each file in a Svelte project defines a single component. You can embed a special markup syntax in the HTML of the component for rendering lists of elements and conditional rendering. There is also a lightweight API for defining stores. These are custom reactive state containers that trigger updates to the UI when their value changes.

The compiler simplifies the runtime by constructing a tree of vanilla Javascript function calls. That means that when the state changes, only the necessary part of the UI changes rather than needing to render the entire tree and scan for differences. The Svelte community has also developed SvelteKit, which adds the batteries into the Svelte world, providing something along the lines of a Next.js development experience.

SolidJS

Another contender in the reactive compiled Javascript framework world is SolidJS. Solid builds on top of the JSX compiler that React already uses to convert JSX into plain JS function calls. It also adds a rich set of  API functions for constructing a reactive graph of data nodes, a tree whose leaves are rendered JSX. It’s very similar to Svelte conceptually, but its components look quite different. Solid also enforces stricter CQRS than Svelte, since it lacks the two-way data binding facilities of Svelte.

Here’s a SolidJS component:

const CountingComponent = () => {
  const [count, setCount] = createSignal(0);
  return <button onclick={() => setCount(count() + 1)}>Count value is {count()}</button>;
};

Notice how similar this component looks to React with hooks. The first line might as well be a call to useState. The only real difference is that you use a getter function instead of a plain value to access that state. Those function calls within the JSX are where Solid steps in and inserts its reactive magic.

However, there’s a dramatic difference in Solid’s approach. This component function will only ever run once per instance of the component. If you were to insert a console.log somewhere before the return, you would only see the output once. The job of a Solid component is to set up any reactive data nodes and return the initial state of the UI.

Solid takes care of keeping those reactive nodes and the UI in sync as changes propagate through the graph. This makes the conceptual model of refs and memoized values significantly more straightforward. It also eliminates the need for restrictions like the “rules of hooks.” In React, the entire component and every hook in it must run on every render. Not so in Solid. That’s a win for both conceptual purity and performance. SolidJS comes out nearly as fast as writing a UI in vanilla JS.

Imba

Imba takes the idea of compiling for the web to the next level: it’s an entirely new language that just happens to compile to Javascript. It has its own syntax and semantics, both inspired by Ruby. In fact, the project started as an attempt to port Ruby to the client-side. What makes Imba unique among programming languages is that DOM elements are essentially first-class language constructs. Components and DOM elements are baked into the core of the language itself, basically making it a Turing complete DSL for UI development.

Imba also has a unique implementation compared to the other two frameworks mentioned. Rather than constructing a reactive graph that terminates in compiler-generated DOM manipulations, Imba uses the idea of a “memoized DOM.”

The compiler transforms components, declared by the tag keyword, into classes with a render method. The first time this render method is called, it inserts the DOM nodes it needs and holds references to them. Subsequent calls just synchronize the DOM with the component’s state. That way, the Imba runtime can basically “re-render” the entire UI tree any time a browser event occurs and guarantee that the UI is in sync with its state. Imba separates relatively expensive setup with relatively cheap updates. That means this full-screen render can run quickly and often, without complex state management approaches.

Here’s a counter component defined in Imba:

tag app-counter
  prop count = 0
  <self>
    <button @click=count++> "clicks: {count}"

Imba is extremely terse compared to the other frameworks mentioned because it went all in and created its own grammar, custom-designed to represent interactive UIs. Its memoized DOM implementation also puts out bundles that are in a similar vein to Svelte and just as snappy.

React Alternatives in 2022

The above libraries can beat React pretty handily in a variety of metrics like out-of-the-box performance, bundle size, or SLOC. Some of them offer conceptually clearer mental models than React’s “run on every render” approach. That said, there are still a lot of reasons to choose React and Typescript over these frameworks for now. React is a very mature ecosystem. It has an enormous, highly-active community, and full support and active development from one of the largest players in tech.

For a company like Atomic, building projects in React and Typescript means we can roll Atoms on and off of projects with shorter learning curves. To justify recommending an entirely different technical platform, that platform needs an extensive list of pros, commanding productivity wins, and minimal drawbacks.

All three React alternatives are great frameworks to keep an eye on and maybe get familiar with on your next side project. SolidJS and Svelte in particular took the number one and number two spots in State of JS 2021 for developer satisfaction and developer interest. That means they might yet achieve the critical mass of community engagement and pre-defined components that represent React’s strongest selling points. Another possibility is that we’ll see the React team take cues from these newcomers and put out tooling that moves towards compilation and static analysis, removing the venerated virtual DOM altogether.

Sometimes the churn of new web frameworks can feel overwhelming and exhausting. On top of that, the tech community has a habit of reinventing wheels we’ve tried years before. On the other hand, it’s exciting to see the community constantly inspiring one another and building on top of the prior art.