SuperAPI AI 工具集

svelte-lifecycle

前端与建站

查看项目

更新于 10-16 10:56

技能介绍

本技能覆盖 Svelte 5 中仍属核心响应式架构、但并非 Runes 的子系统:生命周期钩子、Stores、Context API、测试体系,以及浏览器支持矩阵与例外情况。

一、用途 适用于需要在组件挂载后访问 DOM 或在销毁前清理、需要在状态变更后等待 DOM 更新、需要跨组件共享响应式状态而不想用模块 import、需要写跨组件异步流、需要用 Context 替代 prop drilling 且在 SSR 下不污染全局、需要为 Svelte 组件编写 Vitest 单元与组件测试或 Storybook stories 或 Playwright e2e、以及需要查询浏览器最低版本与例外特性等场景。

二、生命周期钩子 onMount(fn) 在组件挂载到 DOM 后立即运行,仅在浏览器执行,SSR 时不调用。可返回清理函数,用于清理定时器、AbortController、全局事件监听等。关键约束:onMount 必须接收同步函数才能正确返回 cleanup,async 函数总是返回 Promise,cleanup 不会在卸载时调用。onMount 不必写在组件脚本顶层,但必须只在组件初始化时调用,允许从同一模块内的 helper 函数中调用。 onDestroy(fn) 在组件销毁前立即执行,且在 SSR 组件中也会运行,是四个生命周期钩子中唯一在服务器端执行的钩子。常用于清理 setInterval、取消 fetch、解绑全局事件监听。 tick() 返回 Promise,在所有 pending 状态变更应用到 DOM 后 resolve;若无 pending 则在下一个 microtask resolve。常用于 focus、scroll、measure DOM 或在状态变更后调用第三方命令式 API。 Svelte 4 的 beforeUpdate/afterUpdate 已被弃用,Svelte 5 中虽有 shim 但在 runes 组件中不可用,应改用 $effect.pre() 与 $effect()。Runes 版只在显式读取的状态变化时触发,更精确。

三、Stores Stores 是满足 store 契约的对象:必须有 subscribe(fn) → unsubscribe;可写 store 还需有 set(value)。 writable:第二个参数为 start/stop 函数,第一个订阅者订阅时与最后一个订阅者退订时调用,常用于建立外部连接。 readable:不可从外部 set 的 store,初始值 + start 函数。 derived:从一个或多个 store 派生;异步版本接受 (values, set, update),允许在异步回调里调用 set/update,可返回清理函数,可传第三个参数作为初始值。 readonly(store) 包装为只读视图;get(store) 同步读一次,内部建立订阅、读取、退订,不建议在热路径使用。 Stores 与 $state 的选择:Svelte 5 推荐优先使用 runes。提取可复用逻辑用 .svelte.js 文件 + $state,跨组件共享状态用模块级 $state 对象,复杂异步数据流与 RxJS 互操作使用 Stores,简单计数器两者皆可。简单规则:能用 runes 就用 runes,stores 用于事件流或可观察序列。

四、Context API Context 让父组件向任意深度的后代组件传值,无需 prop drilling。 createContext(推荐,Svelte 5.40+)提供类型安全与无需 key 的用法,返回 get/set 对。备选方案为 setContext/getContext,键和值可以是任意 JS 值。hasContext 判断某个 key 是否存在于当前组件上下文层级;getAllContexts() 返回所有当前上下文的 Map,常用于库的内部实现。 与 state 组合时,应将 $state 对象 set 到 context,不要重新赋值,否则破坏响应式链接,Svelte 会发出警告。 替代全局 state 时需注意 SSR:模块级 $state 在 SSR 下会在请求间共享,造成数据泄漏;Context 是请求隔离的,涉及用户特定数据时优先用 Context。

五、测试 Vitest 单元测试:纯逻辑测试无 DOM;组件测试需在 vite.config.js 设置 test.environment: 'jsdom',并在 VITEST 环境下设置 resolve.conditions: ['browser']。使用 mount、unmount、flushSync 进行组件测试,$effect 在 mount 时不会自动运行,测试中用 flushSync() 强制同步触发。使用 $effect 的测试可借助 $effect.root 包裹并在结束后调用 cleanup。 Storybook:通过 npx sv add storybook 配置,用 play 函数模拟用户交互并断言。 Playwright e2e:在 playwright.config.js 中配置 webServer 启动预览服务器,例如 webServer: { command: 'npm run build && npm run preview', port: 4173 },Playwright 自动起 preview 服务器。

六、浏览器支持 基线目标为 Baseline 2020:Chrome/Edge 87、Firefox 83、Safari 14、Opera 73、Opera (Android) 62、Samsung Internet 14.0、Android WebView 87;Internet Explorer 不支持。例外特性需更高版本:$state.snapshot 需 Chrome/Edge 98、Firefox 94、Safari 15.4;bind:devicePixelContentBoxSize 在 Firefox 需 93,Safari 不支持;flip from svelte/animate 在 Firefox 需 126。

七、常见问题与限制 onMount 清理不执行通常是函数为 async 所致,应改用同步函数并内部 await。store 引用 UI 不更新需用 $store 前缀读取,不要解构。derived 不触发可能是回调里未读取任何 store 值,或数组写法有误。Context 在 SSR 间泄漏因模块级 $state 全局共享,应改用 setContext。Vitest 中 document is not defined 需设置 jsdom 环境。组件 mount 后状态未生效需在 mount 后调用 flushSync()。 其他注意事项:store 必须在组件顶层声明;不要给非 store 变量加 $ 前缀;onMount 是唯一的挂载后钩子,没有渲染后钩子,等待 DOM 用 tick();访问 window/document 必须放 onMount 或 onDestroy;setContext/getContext 必须同步调用,在 setup 阶段,不能在事件处理器内;Context 值若为原始值变更不触发更新,需用 $state 对象或函数 getter;onMount 卸载时先调 cleanup,再调 onDestroy。

八、示例与参考文件 示例文件包括 lifecycle-hooks.md、stores-advanced.md、store-patterns.md、context-advanced.md、testing-vitest.md、testing-playwright.md。参考文件包括 lifecycle-hooks-reference.md、stores-api-reference.md、context-api-reference.md、testing-reference.md、browser-support.md。