Solid – The best JavaScript UI library?

A while ago, I wrote a post on some of the most important advantages of Svelte. Back then, the framework had just received a major update, and it was quite a hot topic to cover. Now, after the dust has settled, Svelte still has a lot going for it, but it also has some drawbacks that previously went unnoticed.

I don’t want to rant over these small issues because that’s not the point of this article, and besides – I really like Svelte! But for your information, these are:

  • TypeScript support – although it’s been added recently, it wasn’t there at the time Svelte exploded in popularity. Thus, most of its still small, but very important for the framework ecosystem will most likely not support it.
  • Syntax differences – Svelte feels good when you get used to it, but because of its compiler-based nature, there are some syntax nuances that newcomers might find a bit awkward, like the dedicated template syntax, $: reactive label (although it is technically valid JS), etc.
  • Small ecosystem – this is a common issue that unless you’re React, Vue, Angular, or [insert your big framework here], or you’re 100% down on Web Components, you’re doomed to experience. Because of Svelte’s recent growth in popularity, it developed a pretty-respectable ecosystem, and because of its good support for Web Components (you can even compile Svelte to such), it’s not as big of an issue, but still, something to keep in mind.

So, Svelte is not ideal – nothing is – and that’s why we have alternatives. If the idea of the compiler is very attractive to you and you want to have top-to-bottom TypeScript compatibility without Svelte’s syntactic gotchas, you might be interested in Solid.

So, Solid (not S.O.L.I.D. principles, but Solid UI library) is “a declarative JavaScript library for creating user interfaces”. So, yet another UI framework? Well, yes, but also no. You see, Solid introduces some nice mixtures of concepts that we haven’t seen before, effectively making itself stand out from the overpopulated UI libraries crowd.

What does Solid have going for it? For me there are a few things: it’s written in and has first-class support for TypeScript, it supports JSX, with additional React vibes like Fragments, async rendering, and hook-like functionalities, and last but not least – it’s wicked-fast, going toe to toe with vanilla JS!

I hope I sparked your interests. Now, let’s examine an example Solid component.

// index.tsx
import { Component, createState, onCleanup } from "solid-js";
import { render } from "solid-js/dom";

const App: Component = () => {
  const [state, setState] = createState({ count: 0 });
  const timer = setInterval(
    () => setState("count", (count) => count + 1),
    1000
  );

  onCleanup(() => clearInterval(timer));

  return <div>{state.count}</div>;
};

render(() => <App />, document.getElementById("app"));

Above you see a simplistic counter component. If you’ve worked with React before it should feel somewhat familiar to you.

We create our App component through the use of an arrow function, with a directly-specified type. It’s a little tidbit to remind you that Solid works great with TypeScript.

Next up you can notice the use of the createState() function, together with familiar array destructuring pattern.

This might look a lot like React hooks, but only on the outside. On the inside, there are no “rules of hooks” to oblige to and no issues or confusion around stale closures. That’s because the components in Solid are run only once, leaving reactivity and all the re-executing to specialized parts of the code (like callback passed to “Solid hooks”). To make it even more clear, React invokes the render() method or its functional component equivalent on every re-render, whereas Solid uses its component function as sort-of a “constructor”, which runs only once, to set up all the other reactive parts.

So, we’ve got our state. Now, we use the usual setInterval() function for the counter functionality, and setState() in a reducer-like manner (one of many possible ways to use setState() in Solid), to update the state.

Lastly, we use the hook-like onCleanup() function to register the callback for handling component disposal. Remember, because the core component function is run only once, “hooks” such as onCleanup() are the only way to handle reactive behaviors.

Now, just return the JSX element, render the component and you’re done! Isn’t that complicated, is it?

So, this was just a simple demo to give you some basic understanding of how things look like. For more in-depth guidance check out the official docs, or drop a comment if you’d like to see a full-blown tutorial.

But right now, I’d like to point out a few things that you should keep in mind if you’re willing to try out Solid.

First off, I know I repeat myself, but the fact that the component function is run only once is very, very important. Because Solid uses JSX and is inspired by React, it’s safe to assume that the developers who’d like to use it would be at least somewhat familiar with React and could (possibly) be confused as to why their code isn’t working properly. Knowing about this difference is crucial to get accustomed to the Solid’s approach.

Next up, because Solid is a compiler, it requires additional setup for proper development experience. The easiest way to do this is through a Babel plugin (babel-preset-solid), or by starting with a pre-configured boilerplate:

 npm init solid app my-app

Because modern web development already relies heavily on tools such as Babel, adding another plugin shouldn’t be much of a problem.

Lastly, there are even more things to remember about Solid’s reactivity. Because of heavy optimizations and compiler-based design, there are a few gotchas when working with the state. The most important of which is that you shouldn’t destructure the state, like so:

const { count } = state;

The value derived from destructuring won’t be reactive, and thus won’t be updated when used in JSX. If you really can’t stand constantly having to enter the full state property path, then (apart from having some truly unwieldy state object), you can still handle that like so:

const count = () => state.count;

// later
count();

What you do is essentially creating a thunk (or simply a shortcut) to access the state property. It might be a bit of a waste when dealing with simple states, but can also be really helpful when dealing with 2 or more levels of depth.

But for really simple, one-property states like in the previous example, using objects is an overkill all together. For such cases, Solid provides so-called Signals“atomic immutable cells that consist of a getter and setter”. Basically, a tiny version of state objects, but with a few differences.

import { createSignal } from "solid-js";

const App = () => {
  const [getCount, setCount] = createSignal(0);
  //...

  return <div>{getCount()}</div>;
};

The createSignal() method, returns a pair of functions, from which the first one can be used to access the hold value and the second one to set it.

As you can see, signals are somewhat like a dumb-down version of an object-based state, but only somewhat. You see, Solid uses signals as building blocks for the more advanced reactive functionalities. This includes the object-based state, which at its core is a proxy composed of smaller on-demand signals.

To summarize, if you’re willing to give Solid a try, then it’s quite important to understand its concepts for creating efficient code without compromising too much on development experience.

Before we declare Solid “the next big thing”, or the “best JS UI library”, it’s worth pointing out some of its drawbacks, which honestly there aren’t that many.

From the Solid’s as a UI library standpoint, we might argue that all the API and syntax gotchas I’ve listed, as well as the ones that I didn’t, can be considered a drawback. However, we can’t expect a simple UI library to go against the very nature of software. The limitations of both JavaScript itself, as well as Solid’s compiler-based design, do require some tiny compromises. Which still, at least in my opinion, once you get used to, they shouldn’t be much of an issue.

Secondly, of course, the ecosystem is small. At the time of writing the library has about ~4K GitHub stars, and a fair bit of articles have been written about it. But there’s still little to no ecosystem developed around it. There’s no component library as Vuetify is for Vue and Material UI for React. All you have is what you write, plus the Web Components if you’re willing to use those.

And lastly, I’d say the docs are quite detailed and explain the topic quite well, but they’re only Markdown files living in the GitHub repo with no flashy landing page or anything like that. I know, I know – I’m nitpicking right now, but there needs to be some “ethical marketing” done to get developers interested in a library – otherwise, you’ll only learn about it from benchmarks and articles like this one. The docs are already good enough, the logo is looking nice, and there’s a fair bit of example projects ready for you to see, just – there’s no landing page.

To wrap this up, Solid is a really promising UI library with tons of advantages. The familiarity of JSX and React concepts and the speed and bundle size of Svelte make it seem like an ideal UI library.

The few drawback that Solid has either aren’t that bad, or can be easily fixed, as the library continues to evolve.

Overall, it gets my solid recommendation (see what I did there?), and I highly recommend you check it out. Oh, and come back after you do and let me know your thoughts in the comments below!

For more up-to-date web development content, be sure to follow me on Twitter, Facebook or through my newsletter. Thanks for reading and I wish you S.O.L.I.D. coding!

Author: admin

Leave a Reply

Your email address will not be published.