Svelte Store如何根据会话类型动态绑定响应式inputs属性
Svelte Store 动态切换inputs数据源实现方案
核心思路:不要将inputs作为静态值存入基础writable store,而是利用Svelte内置的derived(派生)store,根据当前会话类型自动订阅对应输入数据源,切换会话时自动完成旧数据源的清理、新数据源的订阅,上层组件完全无感知。
步骤1:封装不同场景的输入数据源
先将两类输入逻辑封装为符合Readable store规范的工厂函数(方便切换时自动创建/销毁实例,避免冗余事件监听、无效网络连接):
import type { Readable } from 'svelte/store'; import { readable, writable, derived } from 'svelte/store'; // 本地键盘输入数据源 const createLocalInputSource = (): Readable<string[]> => readable([], (set) => { let keys: string[] = []; const onKeydown = ({key}: KeyboardEvent) => { if (keys.includes(key)) return; keys = [...keys, key]; set(keys); } const onKeyup = ({key}: KeyboardEvent) => { if (!keys.includes(key)) return; keys = keys.filter(k => k !== key); set(keys); } document.addEventListener('keydown', onKeydown); document.addEventListener('keyup', onKeyup); // 清理函数:取消订阅时自动解绑事件 return () => { document.removeEventListener('keydown', onKeydown); document.removeEventListener('keyup', onKeyup); } }) // 网络输入数据源,按实际业务替换内部逻辑 const createNetworkInputSource = (): Readable<string[]> => readable([], (set) => { // 示例:通过WebSocket拉取实时输入 const ws = new WebSocket('wss://你的业务地址/session/inputs'); ws.onmessage = (event) => { set(JSON.parse(event.data)); } // 清理函数:取消订阅时自动断开连接 return () => { ws.close(); } })
步骤2:重构自定义Session Store
基础writable store仅存储session、sessionType这类核心状态,再通过derived派生出最终对外暴露的store,自动根据会话类型匹配输入源:
// 补全原有类型、枚举定义 enum SessionState { RUNNING, PAUSED, ENDED } enum SessionType { LOCAL, NETWORK } type Session = { state: SessionState } export type SessionStore = { session?: Session, sessionType?: SessionType, inputs: string[] } // 初始值 const initialValue = (): Pick<SessionStore, 'session' | 'sessionType'> => ({ session: undefined, sessionType: undefined }) // 模拟原有网络会话创建方法 async function createSession(): Promise<Session> { return {state: SessionState.RUNNING} } export function makeSessionStore() { // 核心store只存非动态的基础状态 const coreStore = writable(initialValue()); const {set, update} = coreStore; // 派生最终store,自动切换输入源 const store = derived( coreStore, ($core, set) => { // 默认无激活会话时,inputs为空数组 set({...$core, inputs: []}) // 匹配当前会话对应的数据源 let inputSource: Readable<string[]> | null = null; switch($core.sessionType) { case SessionType.LOCAL: inputSource = createLocalInputSource(); break; case SessionType.NETWORK: inputSource = createNetworkInputSource(); break; } // 订阅数据源,同步inputs值;切换时自动执行上一个数据源的清理逻辑 if (inputSource) { return inputSource.subscribe(inputs => { set({...$core, inputs}) }) } }, {session: undefined, sessionType: undefined, inputs: []} as SessionStore ) return { subscribe: store.subscribe, createLocalSession: () => update(() => ({ session: {state: SessionState.RUNNING}, sessionType: SessionType.LOCAL })), createNetworkSession: async () => { const session = await createSession(); update(() => ({session, sessionType: SessionType.NETWORK})) }, reset: () => set(initialValue()) } } // 导出全局单例 export const sessionStore = makeSessionStore();
使用方式
上层组件完全不需要感知数据源切换逻辑,直接订阅store即可:
<script> import { sessionStore } from './session'; </script> <!-- 本地会话显示键盘输入、网络会话显示远端输入,自动切换 --> <p>当前输入:{$sessionStore.inputs.join(' + ')}</p>
逻辑说明
- 会话类型切换时,derived会自动取消上一个输入源的订阅,触发对应清理函数(解绑键盘事件、断开WebSocket等),无内存泄漏
- 重置会话、无激活会话时,inputs自动回落为空数组
- 后续如果新增其他会话类型,只需要新增对应输入源工厂、在switch分支加匹配规则即可,上层代码无需改动
内容的提问来源于stack exchange,提问作者code-gorilla
相关产品推荐
相关产品推荐

