Skip to main content

Command Palette

Search for a command to run...

An Intro to Solid.js for React Developers

A quick introduction of the similarities, differences, and gotchas of solid.js for React developers

Published
6 min read
An Intro to Solid.js for React Developers

In the 2021 state of JS survey result, solid.js, in its debut appearance, surprised many by jumping straight to the top of the satisfaction score. It beat out not just React but Svelte, the 2020 satisfaction leader. While React still maintains a significant market share, ignoring solid.js would be a mistake.

Solid feels very familiar to react developers

Let's look at this arbitrary counter app written in solid.js:

function Counter() {
  const [count, setCount] = createSignal(0);
  return (
    <div>
      <p>The current count is: {count()}</p>
      <button onClick={() => setCount((x) => x + 1)}>Plus</button>
    </div>
  );
}

I am confident that any React developer can understand everything in the above component, despite never seeing solid.js before. This familiarity is because solid.js has an API familiar to React Developers. For one thing, solid.js utilizes JSX, which means elements and components can be composed in many of the same familiar ways that React developers have built an intuition for. For example, we can make this arbitrary Welcome component using just our intuition from building React Apps:

function Welcome(props) {
  return <p>Welcome, {props.name}</p>;
}

Solid.js also utilizes primitives with an API that is very similar to how one would use React hooks. The API of many of solid's reactive primitives are almost identical to their React Hook counterparts.

It's important to point out that solid.js is not attempting to follow React's API one-to-one. You cannot take a React app and start using it in solid.js. It does, however, have an API that is familiar to your average React developer, which makes the learning curve much nicer.

It's all about the primitives

Despite its superficial similarities, what makes solid.js unique is the ways that it is not like React. One of those ways is that, unlike React, the component is not the foundation of solid.js apps. Solid.js proudly describes its components as "vanishing components." Components are helpful for code organization and cease to exist once the initial render occurs.

For solid.js, it's all about the primitives. Solid.js has a suite of "fine-grained reactive primitives." These primitives can feel very similar to React Hooks, but they are not hooks. In React, hooks are dependent upon the React component lifecycle and require you to have at least a rudimentary understanding of the Virtual DOM and the React render lifecycles. This dependency on the React lifecycle is why there are so many "rules of hooks" that you need to know to use them correctly. Let's take this React Component, for example:

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `The current count is: ${count}`;
  }, [count]);

  return (
    <div>
      <p>The current count is: {count}</p>
      <button onClick={() => setCount((x) => x + 1)}>Plus</button>
    </div>
  );
}

Despite how simple this component is, there are several rules you need to remember, and forgetting any of them can cause unwanted problems. Solid's reactive primitives, on the other hand, just work. They can be called conditionally, and they don't even need to be called in a component themselves. The above counter component can be rewritten in solid.js like this:

const [count, setCount] = createSignal(0);

createEffect(() => {
  document.title = `The current count is: ${count()}`;
});

function Counter() {
  return (
    <div>
      <p>The current count is: {count()}</p>
      <button onClick={() => setCount((x) => x + 1)}>Plus</button>
    </div>
  );
}

We have moved all the reactive primitives outside of the component itself in the above component. We can do this because Solid's reactive primitives themselves, not the components, are what solid.js is built on and where the "magic" happens.

Reactivity VS Virtual DOM

Like many popular frameworks, React is built on the concept of a "Virtual DOM." A virtual DOM is an in-memory representation of the actual DOM. The idea is that doing things in memory is less expensive than working with the actual DOM, so one can run and re-run components multiple times, making changes to this virtual DOM. Only if there are actual differences between the virtual DOM and the real DOM will React reconcile those changes from the virtual DOM to the actual DOM. You are literally hooking into the React Virtual DOM Lifecycle when you use hooks.

Solid.js, on the other hand, depends on "fine-grained" reactivity. When you write a JSX expression that relies on a reactive signal, for example, only the part of the JSX that depends on that signal's value is wrapped in a function that is re-run if that signal changes. The same goes for effects run in the createEffect primitive. If the effect has a dependency on one or more reactive values, it will be re-run only if the reactive value changes. There is no need for a dependency array since solid knows in advance if the value can be changed and will re-run only those effects that depend on the changed reactive values.

This is why solid components are "vanishing," and reactive primitives can be called outside of the component. After the initial render, only those fine-grained parts of the app will continue to exist.

Gotchas coming from React

This difference in how the two frameworks work under the hood can lead to two of the biggest "gotchas" that React developers fall into when starting with solid.js. The first gotcha is you need to re-teach yourself that components don't ever get re-run. Those things that we have taught ourselves that we should (and shouldn't) do in a React component no longer apply in Solid.js. We don't need hooks like useCallback and useRef, because the component never re-runs. Instead, we can just assign them to variables like any other JavaScript code we write:

function MyForm() {
  const handleSubmit = (e) => {
    /* handl submit */
  };

  let myInput;
  // use onMount or createEffect to read after connected to DOM
  onMount(() => myInput.focus());

  return (
    <form onSubmit={handleSubmit}>
      <input ref={myInput} />
    </form>
  );
}

The second is that you can break the fine-grained reactivity if you destructure the props. The props object may or may not have reactive values in them. By destructuring them, that reactivity can be lost. So instead of writing code like this:

function Greeting(props) {
  const { greeting, name } = props;
  return (
    <h3>
      {greeting} {name}
    </h3>
  );
}

It would be best if you wrote it like this:

function Greeting(props) {
  return (
    <h3>
      {props.greeting} {props.name}
    </h3>
  );
}

Or you can utilize solid's mergeProps or splitProps utility functions, which allow you to merge or split objects with reactive values without breaking reactivity.

When React was introduced, it challenged the best practices of the day. That challenge has had a lasting impact on how we write web applications. Solid is here to continue to push us in that same direction that React started.

B

Seems much EASIER than React IMO - your dropping some of those concepts that seemed to me not only unnecessary but maybe uncalled for and solid.js seems to be the answer to some of those.

I'm digging deeper into this - although React has retrained my brain in many concepts (primarily to think in jsx / componential separation) I think solid.js will solidify some of these concepts into a cleaner structure within the code. We shall see.

I vote MORE Solid.js write ups like a part two of this one!! Like this if you agree!! Thanks so much for this! MORE content like this please - your way of breaking it down in comparisons' is much easier to grasp the concepts here and I'm diggin it!

2
T

Thanks so much. I would love to do more. Look out for it soon hopefully

V

Didn't know it'd be that familiar to react.

A

It would be great if u explain the need of now destructuring props in solidjs , from what i know , they are using some proxies to track down it , so ...

reference - https://docs.solidjs.com/guides/getting-started-with-solid/adding-interactivity-with-state#managing-basic-state-with-signals

2
T

To make accessing prop values work with the reactivity, Solid, under-the-hood, uses proxies with getters and setters. This means that if you access a reactive value outside of a solid.js tracking scope, the reactivity is broken: https://www.solidjs.com/tutorial/props_defaults

1
I

Great article! I love Solid.js and hope it skyrockets in popularity and usage.

Just FYI your first example in the Gotchas section is missing the ref.

It should be:

<input ref={myInput} />
1
T

Thank you, It is fixed in the example

1
D

I've been interested in checking out Solid more and more. Thanks for sharing!

1