文档
Solid.js 入门教程:细粒度响应式编程
一、Solid.js 是什么?
Solid.js 由 Ryan Carniato 创建,外观与 React 很像(JSX、组件、Hooks 风格 API),但底层机制完全不同:
- 无虚拟 DOM:组件只执行一次,JSX 编译为真实 DOM 操作
- 细粒度响应式:不是"状态变了 → 重新渲染组件",而是"状态变了 → 直接更新 DOM 中用到该状态的那个文本节点"
- 性能极致:在 JS 框架 Benchmark 中长期排第一
核心哲学
"组件是组织的概念,不是渲染的概念"
二、Signal:最小响应单元
import { createSignal } from "solid-js";
// 返回 [getter, setter] 对
const [count, setCount] = createSignal(0);
count(); // 读取 → 自动追踪
setCount(1); // 设置 → 通知所有依赖
setCount(c => c + 1); // 函数式更新
Signal vs React State
React useState |
Solid createSignal |
|
|---|---|---|
| 存储位置 | 组件实例 | 闭包(独立于组件) |
| 读取方式 | count(值) |
count()(函数调用) |
| 更新效果 | 组件重新渲染 | 仅更新依赖此 signal 的 DOM |
| 可在组件外 | ❌ | ✅ |
三、Effect:副作用自动追踪
import { createEffect } from "solid-js";
createEffect(() => {
// 自动追踪内部访问的所有 signal
console.log(`新值:${count()}`);
localStorage.setItem("count", String(count()));
// 当且仅当 count() 变化时执行
});
Effect 的自动清理
createEffect(() => {
const timer = setInterval(() => console.log("tick"), 1000);
// Solid 自动追踪首次执行后的返回值
onCleanup(() => clearInterval(timer));
// 当 effect 重新执行或组件销毁时自动调用
});
四、派生状态:Memo
import { createMemo } from "solid-js";
const [items, setItems] = createSignal([1, 2, 3]);
// 仅在依赖变化时重新计算,否则返回缓存值
const total = createMemo(() => {
console.log("重新计算 total");
return items().reduce((sum, n) => sum + n, 0);
});
// 多次 total() 只会计算一次
五、控制流组件
Solid 用组件而非指令做条件/循环(因为组件只在需要时执行):
import { Show, Switch, Match, For, Index } from "solid-js";
<Show when={user()} fallback={<p>请登录</p>}>
<Dashboard user={user()} />
</Show>
<Switch>
<Match when={status() === "loading"}><Spinner /></Match>
<Match when={status() === "error"}><Error message={error()} /></Match>
<Match when={true}><Content /></Match>
</Switch>
{/* For:按值追踪,适合不可变列表 */}
<For each={todos()}>
{(todo, index) => <li>{index()}: {todo.text}</li>}
</For>
{/* Index:按索引追踪,适合大量静态元素 */}
<Index each={photos()}>
{(photo, index) => <img src={photo().url} />}
</Index>
六、生命周期
import { onMount, onCleanup } from "solid-js";
onMount(() => {
// DOM 已挂载
fetch("/api/data").then(/* ... */);
});
onCleanup(() => {
// 组件销毁前
// 取消订阅、清除定时器等
});
七、资源管理:createResource
import { createResource } from "solid-js";
const [userId, setUserId] = createSignal(1);
const [user, { mutate, refetch }] = createResource(userId, async (id) => {
const res = await fetch(`/api/users/${id}`);
return res.json();
});
// user() → undefined(loading)或数据
// user.loading → true/false
// user.error → Error 或 undefined
// mutate(optimisticData) → 乐观更新
八、与 React 的关键区别
| React | Solid |
|---|---|
useState = 组件级状态 |
createSignal = 独立于组件 |
useEffect = 依赖数组手动指定 |
createEffect = 自动追踪 |
useMemo / useCallback 手动优化 |
createMemo 自动缓存 |
| 组件 re-render = 函数重新执行 | 组件函数只执行一次 |
需要 key 做列表 diff |
For 按值追踪,无需 key |
九、思考题
- 为什么
createSignal可以在组件外部使用?这对状态管理意味着什么? - 如果你在
createEffect中不读取任何 signal,effect 会执行几次? - Solid 的
For和Index有何区别?在什么场景该用哪个?