SuperAPI AI Directory

solidjs

Frontend & websites

View repository

Updated 10-15 21:49

About this skill

SolidJS

SolidJS is a declarative JavaScript library for building user interfaces without a Virtual DOM, compiling templates to direct DOM operations powered by fine-grained Signals reactivity.

When to Use

  • High-Performance Reactive Web Applications: Fine-grained reactivity without Virtual DOM overhead.
  • Real-Time Dashboards & Data Streaming: Rapid UI updates directly mapped to granular DOM mutations.
  • Low-Memory Resource-Constrained Devices: Embedded screens, smart TVs, and low-end mobile devices.
  • SolidStart Full-Stack Web Development: Building SSR/SSG full-stack applications with JSX simplicity.

Quick Start

import { createSignal, onCleanup } from "solid-js";

export function Counter() { const [count, setCount] = createSignal(0); const timer = setInterval(() => setCount((c) => c + 1), 1000); onCleanup(() => clearInterval(timer));

return Count: {count()}; }


## Core Concepts

### Fine-Grained Reactive Primitives: Signals & Memos

Components execute only once; signals trigger targeted DOM node updates:

```tsx
import { createSignal, createMemo, createEffect, onCleanup } from "solid-js";

export function Counter() {
  const [count, setCount] = createSignal(0);
  const doubleCount = createMemo(() => count() * 2);

  createEffect(() => {
    console.log(`Current count: ${count()}, Doubled: ${doubleCount()}`);
  });

  const timer = setInterval(() => setCount((c) => c + 1), 1000);
  onCleanup(() => clearInterval(timer));

  return (
    <div class="p-4 border rounded">
      <h3>Count: {count()}</h3>
      <p>Double: {doubleCount()}</p>
      <button onClick={() => setCount((c) => c + 1)}>Increment</button>
    </div>
  );
}

Asynchronous Data with createResource & Suspense

Declarative async data fetching with Suspense boundaries:

import { createResource, Suspense } from "solid-js";

interface UserProfile {
  id: number;
  name: string;
}

const fetchUser = async (id: number): Promise<UserProfile> => {
  const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
  return res.json();
};

export function UserView(props: { userId: number }) {
  const [user] = createResource(() => props.userId, fetchUser);

  return (
    <Suspense fallback={<p>Loading user profile...</p>}>
      <div>
        <h3>{user()?.name}</h3>
        <p>User ID: {user()?.id}</p>
      </div>
    </Suspense>
  );
}

Control Flow with For, Show, and Switch

Optimized DOM rendering primitives replacing array .map():

import { For, Show } from "solid-js";

export function ProductList(props: {
  products: { id: number; name: string; inStock: boolean }[];
}) {
  return (
    <div>
      <Show
        when={props.products.length > 0}
        fallback={<p>No products found.</p>}
      >
        <ul>
          <For each={props.products}>
            {(product) => (
              <li>
                {product.name} -{" "}
                {product.inStock ? "Available" : "Out of Stock"}
              </li>
            )}
          </For>
        </ul>
      </Show>
    </div>
  );
}

Common Patterns

Fine-Grained Reactive Store for Complex Objects

Problem: Re-rendering an entire list when only a single property of one item changed.

Solution: Use createStore for deep nested mutations:

import { createStore } from "solid-js/store";

export function TodoApp() {
  const [todos, setTodos] = createStore([
    { id: 1, text: "Learn SolidJS", done: false },
    { id: 2, text: "Build App", done: false },
  ]);

  const toggleTodo = (id: number) => {
    setTodos(
      (todo) => todo.id === id,
      "done",
      (done) => !done
    );
  };

  return (
    <ul>
      <For each={todos}>
        {(todo) => (
          <li onClick={() => toggleTodo(todo.id)}>
            {todo.text} - {todo.done ? "✓" : "○"}
          </li>
        )}
      </For>
    </ul>
  );
}

Best Practices

Do:

  • Use <For> and <Show> instead of .map() or ternary operators to minimize unnecessary DOM recreations.
  • Remember that Solid components run only once; never destructure props directly (use props.title or mergeProps).
  • Use createResource for async data loading with <Suspense>.
  • Call onCleanup inside effects and primitives to clear timers and event listeners.

Don't:

  • Destructure props in component argument signatures; it breaks fine-grained reactivity tracking.
  • Update signals inside createMemo; memos must remain pure derivation functions.
  • Use Virtual DOM assumptions (like re-rendering whole component trees).

Troubleshooting

Error Cause Solution
Signal value not updating in UI Destructuring props or signals, breaking reactive tracking. Access props directly (props.name) or use splitProps().
TypeError: count is not a function Accessing signal as a raw value instead of calling getter count(). Call signal as function: count().
Component function executes only once Solid components are setup functions, not render functions. Place reactive logic inside effects or JSX getters, not bare component body.

References