You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:33:22