SolidJS 基础知识参考字典

要点

本篇是 SolidJS 及其配套生态的条目式速查,按用途分六组:响应式原语(solid-js)、控制流组件、组件与 props、状态库(solid-js/store)、路由与数据(@solidjs/router)、SolidStart 工程;文末有全量速查表,可只搜表定位条目。版本基线:solid-js 1.9.10、@solidjs/router 0.15.4、SolidStart 1.2.0(截至 2025-11-20 的稳定线),仅在此基线成立的特性单独标注。路由与数据的机制讲解不在本篇重复,见SolidStart 路由与数据;框架定位与响应式模型见开山篇SolidJS 入门。

响应式原语组(solid-js)

API 一句话用途 有什么坑
createSignal(v) 声明状态,返回 [取值函数, 写入函数] 读值必须调用 count();把 count 当值传出就丢追踪,传 count 才保活性
createMemo(fn) 派生值,依赖变化自动重算并缓存 派生链里再写别的信号会造成级联更新,保持纯读
createEffect(fn) 副作用,自动追踪执行中读到的信号 能从别的值算出来的别放这里;那是 createMemo 的活
createResource(fn) 异步资源,集成 Suspense/ErrorBoundary 读 data() 的组件必须在 Suspense 内,否则整树进入等待
on(deps, fn) 显式声明依赖的副作用 默认首次执行,不要首跑要传 { defer: true }
onMount(fn) 首次渲染后执行一次 没有”依赖数组”概念——组件函数只跑一次
onCleanup(fn) 注册清理逻辑,作用域销毁时执行 计时器、订阅、事件监听都走它,没有 useEffect 式的 return 清理
onError(fn) 作用域级错误捕获 兜不住子树内已被 ErrorBoundary 处理的错误
untrack(fn) 读信号但不建立依赖 effect 里只想”看一眼”大对象时用,防误触发
batch(fn) 合并多次写入为一次更新 逐条 set 引发多次更新时才需要
createDeferred(v) 延迟到空闲时计算的派生值 大计算让路给渲染的场景
createContext / useContext 跨层级共享数据 context 值要保持响应性就传取值函数,传快照同 signal 的坑

createSignal:取值函数是心智根基

import { createSignal } from "solid-js";

const [count, setCount] = createSignal(0);
setCount(count() + 1);        // 用当前值写
setCount(c => c + 1);         // 基于前值写,批量场景更稳

一句话语义:声明”这个值变了,读它的地方要更新”。坑在传递:JSX 里 {count()} 是读值并建立订阅;value={count()} 传的是快照,value={count} 传的是取值函数——想让子组件里的变化触发更新,读取必须发生在渲染表达式里。

createResource:什么时候用它而不是 query

const [data, { refetch, mutate }] = createResource(() =>
  fetch("/api/boards").then(r => r.json())
);
data.loading; data.error; refetch();   // 四件套:数据、加载态、错误、手动重取

一句话语义:把 Promise 变成带加载态的响应式资源。分工判断:单组件内部的一次性异步用 createResource;路由级、需要按 key 去重缓存的数据走 router 的 query(见路由组),后者才能在多组件间共享缓存并在 action 后自动刷新。

控制流组件组

组件 一句话用途 有什么坑
条件渲染,可带 fallback 切换即销毁重建;keyed 开启后对象变化也重建
列表渲染,按引用追踪每项 适合对象数组;重排时移动 DOM 节点而非重建
列表渲染,按索引追踪 原始值数组必须用它;子项是取值函数要调用
/ 多分支条件渲染 命中第一个 when 为真的分支,注意分支顺序
动态组件或标签 换标签渲染场景,比三元堆叠清晰
渲染到 DOM 其他位置 弹窗挂 body 用;事件仍走 Solid 上下文
异步等待边界 资源读取要落在它内部才触发 fallback,边界越细首屏越早
错误兜底边界 fallback 用函数可拿到错误对象与重置回调

For 还是 Index:看数组元素是什么

<For each={todos()}>{(todo) => <li>{todo.title}</li>}</For>
<Index each={cells()}>{(cell, i) => <td>{cell()}</td>}</Index>

一句话语义:For 按引用追踪,对象数组重排时直接移动现成节点;Index 按索引追踪,元素本身被替换时也只更新那一格。坑:For 渲染字符串/数字数组时没有引用可追,改动一个元素是整列表重建——原始值数组换 Index。

组件与 props 组

API 一句话用途 有什么坑
props 对象 属性访问带 getter,保持响应性 解构 props 是头号 bug 来源,开山篇已详述
splitProps(props, keys) 拆出本地属性与透传属性 拆出来的仍是响应式引用,不是退化成值
mergeProps(…sources) 合并多来源 props(含默认值) 包装组件别用展开运算符合并,会丢响应性
children(fn) 访问 JSX 子元素 children 是取值函数,要调用 children() 才是内容
lazy(() => import()) 代码分割的组件 要在 Suspense 下等待,否则报 hydration 错误
createComponent(fn) 创建组件的底层入口 业务代码不直接写,做包装库时才用到

splitProps:解构 props 的正牌替代品

function Card(props) {
  const [local, rest] = splitProps(props, ["title"]);
  return <li {...rest}>{local.title}</li>;   // title 留下渲染,其余透传
}

一句话语义:把 props 拆成”本组件要用的”和”继续传下去的”,两边都保持响应性。坑:const { title, ...rest } = props 这种 React 习惯写法会同时弄死两边——title 变成快照,rest 丢掉 getter。

状态库组(solid-js/store)

API 一句话用途 有什么坑
createStore(init) 深层响应式状态对象 更新走 setState 路径语法,别整对象替换
setState(path, v) 路径级精确更新 setState(“cards”, 0, “title”, v) 只动一个节点,订阅该节点的才更新
produce(fn) 类 immer 的变更写法 配 setState(“list”, produce(list => …)) 用,单独用没意义
reconcile(data) 整对象替换时的差量对齐 服务端全量数据进来时用它,避免全树重渲
unwrap(store) 取出无代理的原始对象 结果不再响应式,只用于序列化或比对
createMutable(init) 可直接改的响应式对象 与 signal 风格混用会难追踪,团队内二选一

createStore:路径更新是差量的来源

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

const [state, setState] = createStore({ cards: [{ id: 1, title: "设计" }] });
setState("cards", 0, "title", "设计评审");                          // 精确到一个字段
setState("cards", produce(l => l.push({ id: 2, title: "开发" })));  // 数组操作

一句话语义:把嵌套状态变成可按路径订阅的对象树。坑:写成 setState(state => ({ cards: [...state.cards] })) 整体替换,差量更新优势就没了——要么路径更新,要么配 reconcile。

路由与数据组(@solidjs/router 0.15.x)

API 一句话用途 有什么坑
Router / root 路由容器与根布局 root 里必须包 Suspense,否则 hydration 报错
FileRoutes routes 目录转路由定义 来自 @solidjs/start/router;只收 UI 路由不含 API 路由
站内链接,走客户端导航 裸 a 标签会整页刷新;activeClass 标激活态
useNavigate() 编程式导航 navigate(“/x”, { replace: true }) 替换历史
useParams() 读动态段 返回响应式对象,读 params.id 保持追踪
useLocation() 读 pathname/search/hash/query 在副作用里读它即建立依赖
useSearchParams() 读写查询串 返回 [params, setParams] 元组;setParams 写进 URL
useMatch(() => “/x”) 判断是否命中某路径 导航高亮比手动比 pathname 稳
useBeforeLeave(fn) 离开路由前拦截 要阻止必须调 e.preventDefault(),未保存提醒场景
query(fn, key) 请求级去重缓存的数据读取 key 必须稳定唯一;同名同参共享一份结果
cache(fn, key) query 的弃用别名(0.15.0 更名) 存量代码全局替换为 query 即可,行为一致
createAsync(fn) 把 query 结果接进组件 返回取值函数与 .latest;fetcher 同步读的信号即依赖
action(fn, name) 声明写操作 SolidStart 里函数体首行写 “use server”
useAction(a) 拿可编程调用的 action 拖拽、按钮点击等非表单触发场景
useSubmission(a) 最近一次提交的回执 pending/result/error/input;action 成功后自动 revalidate 本页 query
redirect(path) action 内跳转 用 throw redirect(…) 触发,别当普通函数调用
reload 手动重取数据 配 revalidate 选项指定 key,空数组表示不重取

useSearchParams:筛选状态进 URL 的标准写法

const [params, setParams] = useSearchParams();
setParams({ page: 2 });              // 写进 URL,可分享可后退
<a href={"?page=" + (Number(params.page) || 1) + 1}>下一页</a>

一句话语义:把查询串变成双向绑定的响应式状态。坑:params.page 是字符串或 undefined,参与运算前先转数字;组件卸载不需要清它——状态本来就在 URL 里。

SolidStart 工程组

条目 一句话用途 有什么坑
app.config.ts defineConfig({ ssr, server }) ssr: false 是 SPA 模式;server.preset 是 Nitro 部署目标(node-server/vercel/netlify 等)
vinxi dev 开发服务器(npm run dev) 默认 3000 端口
vinxi build / start 构建与生产启动 node-server preset 产物在 .output/server/index.mjs
“use server” 标记函数只在服务端执行 漏写则整段进客户端产物,数据库连接与密钥一起泄漏
APIEvent API 端点入参 { request, params, fetch },来自 @solidjs/start/server
GET/POST 导出 路由文件导出方法名即端点 与页面同路径时 API 优先,GET 不返回值回落页面
isServer(solid-js/web) 运行环境布尔值 替代 typeof window !== “undefined” 式判断
@solidjs/meta Title/Meta 文档头管理 配 MetaProvider 包住根布局才生效
mount(@solidjs/start/client) 客户端挂载入口 写在 src/index.tsx,不要在这里塞业务逻辑

全量速查表

条目 一句话用途 有什么坑
createSignal 状态 读值要调用;传取值函数不传快照
createMemo 派生缓存 能算出来的别放 effect
createEffect 副作用 清理用 onCleanup
createResource 异步资源 必须在 Suspense 内读
onMount / onCleanup 首跑 / 清理 组件只跑一次,没有依赖数组
untrack / batch 免追踪读 / 合并写入 防误触发与抖动
Show / Switch-Match 条件渲染 切换即销毁重建
For / Index 列表渲染 对象数组 For,原始值数组 Index
Suspense / ErrorBoundary 等待与错误边界 边界粒度决定首屏与兜底范围
props / splitProps 组件入参 解构丢响应性,拆分用 splitProps
createStore 深层状态树 路径更新保差量
reconcile / produce 差量对齐 / immer 式写法 整对象替换必配 reconcile
A / useNavigate 链接与编程导航 裸 a 整页刷新
useParams / useLocation 读路由状态 响应式对象,读即订阅
useSearchParams 查询串读写 值是字符串,先转数字
query(cache 弃用) 去重缓存读取 key 稳定唯一,同参共享结果
createAsync 组件内消费 query fetcher 同步读的信号是依赖
action / useSubmission 写操作与回执 成功后自动 revalidate 本页 query
redirect / reload 跳转 / 手动重取 redirect 要 throw
app.config.ts ssr 与 Nitro preset ssr:false 即 SPA 模式
“use server” 服务端专属函数 漏写就是密钥泄漏
APIEvent / 方法名导出 API 端点 同路径 API 优先

延伸阅读

文件路由与数据 API 的机制讲解见SolidStart 路由与数据;把这些条目组合成完整应用的过程见实战篇用 SolidJS 做一个看板小应用(2025-12-04 发布);按阶段串起本系列与前置知识的路径见SolidJS 学习路线(2025-12-11 发布)。ESM 模块机制不熟的,先补站内Node.js 模块与 ESM;异步与 Promise 基础见Node.js 异步与 Promise。

版本核实(以官方文档为准):截至本文(2025-11-20)稳定线为 solid-js 1.9.10、@solidjs/router 0.15.4、SolidStart 1.2.0(均为 npm 实查版本);cache→query 更名发生于 router 0.15.0,cache 保留为弃用别名;action 成功后自动 revalidate 本页 query、API 路由方法名导出、APIEvent 结构、”use server” 指令均为官方文档描述;solid-js/store 与控制流组件为 1.x 长期稳定 API。安装命令不钉版本号,API 细节以 docs.solidjs.com 当前文档为准。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇