javascriptreactjssolid-js

What is the difference between useState and createSignal?


What are the differences between React's useState and Solid JS's createSignal.

Do Solid's signal has benefits over React's state?

import React, { useState } from "react";

function App() {
    const [counter, setCounter] = useState(0);
    return (
      <div>
        <p>{counter}</p>
        <button onClick={() => setCounter((counter) => counter + 1)}>
          Click Me
        </button>
      </div>
    );
}
import React from "react";
import { createSignal } from "solid-js";

function App() {
    const [count, setCount] = createSignal(0);
    return (
      <div>
        <p>{count()}</p>
        <button onClick={() => setCount(count() + 1)}>Click Me</button>
      </div>
    );
}

Which one is better for performance and mental model?


Solution

  • Solid and React looks the same from the outside since they both use JSX to render UI layer and similar names for their API but in reality that have nothing in common.

    They have totally different premises and different performance characteristics and different execution model.

    React uses VDOM, every state update triggers rebuilding of the whole VDOM tree. But aggressive diffing and patching minimizes the work to be done. Hover component state in React lives inside the component. So, it tries to keep the state intact while breaking apart the structure that holds the state. So, it has full of quirks and unnecessary juggling. it is not only the library but also user space code reflects this shortcoming.

    It is not only keeping state, but also preventing re-renders causes you trouble. Since VDOM causes re-renders with every state update anywhere in the downstream branch, even if you have diffing and batching in place. Say you have socket connection in your application. If you don't take active measures you will be creating new connection with every state update. So, lots of things to consider and lots of things to keep in mind in React's components.

    In Solid, state is isolated from the UI layer even if state lives inside the component and components renders once when the application loads. Components subscribe to state changes automatically if they accesses a signal's value in their body.

    Each signal keeps its own subscribers list in Solid. Updating signal's value notifies its subscribers, including components. A component can re-render as a whole, or can update only the required bits like innerText values, or do nothing at all. It is up to the component what to do when it receives the update notification.

    React components compiles to createElement function calls, and props are kept as objects. In solid, components are compiled into function calls. This makes solid use regular scoping rules. In other words, In solid components can access to their outer scopes but same is not true for React.

    One advantage this brings is that, the state can be kept both inside and outside the component boundary. Any state update will trigger re-run through function calls and small bits and pieces gets updated.

    In Solid, components are there for organizing code, nothing more. There are no re-renders upon state update. All these properties makes Solid component very performant.

    Only downside is you can not use object destructing in Solid components since you rely on function calls to preserve reactivity. Let me give you an example to clarify this further:

    Say a child component accesses count property on a composite state:

    const [state, setState] = createSignal({ count: 0 });
    

    It gets the value when state() is called. Only way to get the count value is calling state(). Here you can get the state value by:

    const count = state().count;
    const { count } = state();
    

    Both works initially, but in second one, you will be assigning value to a local variable. Since there is no re-render upon state update, in Solid you will be stuck with the initial value. Remember state update does not trigger re-render in Solid. But there are workaround and plugins to fix this issue.

    In React VDOM re-renders, meaning you execute the code again, so it does not matter if you destructure or not since whole code block will be re-executed with every state update.

    React is not truly reactive, re-rendering because of VDOM gives you that feeling, while Solid is.

    There are many more differences but I think this suffices to answer your question.

    Solid is fast because of its execution model.

    Solid also has a clear mental model. Code is straightforward and enough to decipher what is going on.

    But for React, it is not only the component's logic you have to know closely and keep in mind while you are programming, but all of its child components because they can also can cause re-renders.

    Say, you imported a child component somewhere 3 level deep inside a component. Any update inside that child component triggers re-render in any of its parent. That is why React has strong emphasis on purity. So, it is not only the component at hand you have to know and keep in mind, but also all of its children. Import a buggy component and you are in trouble.

    In Solid, if you import a troublesome component, bug will be limited to that component and the impact is isolated since it can not trigger re-render.