SolidJS
Getting started with SolidJS is straightforward, especially if you’re already familiar with React. SolidJS is a powerful, fine-grained reactive framework that offers excellent performance and a familiar JSX syntax.
Below are a few videos recommended in the SolidJS documentation that can help you get started:
For a more in-depth understanding, you can also check out the official SolidJS documentation.
Quick Start
Section titled “Quick Start”This guide is designed to bridge the gap between the React and Solid. We’ll show you what’s familiar and, more importantly, explain the fundamental shift in thinking that will help you write clean, incredibly performant Solid applications.
Think of it this way: the “what” (your UI) is familiar, but the “how” (the update mechanism) is different and, once you grasp it, much simpler.
What Will Feel Familiar
Section titled “What Will Feel Familiar”The fundamentals of creating components with JSX and passing props are nearly identical. Solid provides first-class TypeScript support to make this process robust.
- Components are Typed Functions: You build your UI from functions that return JSX. The idiomatic way to type them is with the Component type from solid-js.
- Props are Typed: You can define props for your components just as you would in React, typically using an interface or type alias.
import type { Component } from 'solid-js';
// Define the shape of your propstype GreetingProps = { name: string;};
// Use the Component<T> type for your componentconst Greeting: Component<GreetingProps> = (props) => { return <div>Hello, {props.name}!</div>;};
const App: Component = () => { return <Greeting name="Solid Developer" />;};
The Big Difference: True Reactivity vs. the Virtual DOM
Section titled “The Big Difference: True Reactivity vs. the Virtual DOM”This is the most important concept to understand, and it’s what makes Solid so fast.
In React, when state changes, the component function re-runs, and a Virtual DOM is used to figure out what changed.
In Solid, your component functions run only once to set up the view. They don’t re-run. Instead, Solid uses a reactive system that surgically updates the exact parts of the DOM that need to change.
React (VDOM) | Solid (Reactivity) |
---|---|
State change triggers a component re-render. | Component function runs once. |
A new VDOM is created and diffed. | A reactive signal directly updates the DOM. |
Relies on dependency arrays (useEffect). | Dependencies are tracked automatically. |
”Re-run everything to figure it out." | "Update only what’s necessary.” |
This fundamental difference eliminates the need for dependency arrays and a whole class of bugs related to stale closures.
Mapping React Concepts to Solid
Section titled “Mapping React Concepts to Solid”Here’s a practical, type-safe look at how common React hooks map to Solid’s reactive primitives.
State: useState
→ createSignal
Section titled “State: useState → createSignal”In Solid, you use createSignal
. It’s generic, so it can infer the type from its initial value, or you can provide it explicitly. A signal is a tuple containing an Accessor
(the getter) and a Setter
.
import { createSignal } from 'solid-js';import type { Accessor, Setter } from 'solid-js';
// Type is inferred as 'number'const [count, setCount] = createSignal(0);// count is type: Accessor<number>// setCount is type: Setter<number>
// You can also be explicit, which is useful for complex typesconst [user, setUser] = createSignal<User | null>(null);
The most critical difference for React developers is that the state variable (count
) is an accessor function, not a static value.
// To read the value, you must call the function:<h1>The count is: {count()}</h1>
// This is wrong and will not be reactive:<h1>The count is: {count}</h1>
Why? Calling count()
is how you tell Solid’s reactive system that this part of your UI depends on the signal. It’s how the magic happens without a VDOM.
Side Effects: useEffect
→ createEffect
Section titled “Side Effects: useEffect → createEffect”createEffect
automatically tracks any signals you read inside it. No dependency array needed!
import { createEffect, createSignal } from 'solid-js';
const [count, setCount] = createSignal(0);
// This effect automatically re-runs whenever 'count()' changescreateEffect(() => { console.log('The count is now', count());});
Memoization: useMemo
→ createMemo
Section titled “Memoization: useMemo → createMemo”For deriving reactive values, use createMemo
. It also tracks its own dependencies and returns a read-only Accessor.
import { createMemo, createSignal } from 'solid-js';import type { Accessor } from 'solid-js';
const [count, setCount] = createSignal(5);
// The type of doubleCount is Accessor<number>const doubleCount: Accessor<number> = createMemo(() => count() * 2);
// Use it in your JSX just like a signal<p>Double the count is: {doubleCount()}</p>
A Common Pitfall: Lists and Conditionals
Section titled “A Common Pitfall: Lists and Conditionals”Because your components only run once, you cannot use array methods like .map() directly in your JSX for reactive data. To handle this, Solid provides special, typed helper components.
- For lists, use the
<For>
component. - For conditional rendering, use the
<Show>
component.
These components are reactive and ensure the DOM is updated efficiently.
import { createSignal, For, Show } from 'solid-js';import type { Component } from 'solid-js';
interface User { id: number; name: string;}
const [users, setUsers] = createSignal<User[]>([ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' },]);
const [currentUser, setCurrentUser] = createSignal<User>(users()[0]);
// Correct way to render a list// 'user' is correctly typed as 'User' inside the loop<For each={users()}> {(user, i) => <div>{i() + 1}: {user.name}</div>}</For>
// Correct way to show/hide content// The 'when' prop narrows the type of 'user()' inside the block<Show when={currentUser()} fallback={<p>No user selected.</p>}> {user => <p>Current user is: {user.name}</p>}</Show>