如何在不修改组件导入的情况下替换可写Svelte Store?
实现可切换路径且保持可写性的Svelte Firebase实时Store
核心思路
由于derived store天生只读,无法直接暴露set/update方法,我们需要自定义一个可切换内部实时Store的容器Store:它监听$page的参数变化,动态切换底层的realtimeStore实例,同时对外暴露一致的subscribe/set/update接口,完美保留可写性。
实现代码
1. 创建可切换的Project Store
假设你的realtimeStore工厂函数已经实现了基础的subscribe/set/update方法,基于它封装自定义Store:
import { page } from '$app/stores'; import { realtimeStore } from './path-to-your-realtime-store'; export function createProjectStore() { let currentStore; let unsubscribePage; let unsubscribeCurrentStore; // 订阅逻辑:转发当前活跃的realtimeStore的订阅 function subscribe(run, invalidate) { // 首次订阅时监听page参数变化 if (!unsubscribePage) { unsubscribePage = page.subscribe((newPage) => { const newProjectId = newPage.params.projectId; if (!newProjectId) return; // 清理旧的Store订阅 if (unsubscribeCurrentStore) unsubscribeCurrentStore(); // 创建新的realtimeStore实例 currentStore = realtimeStore(`projects/${newProjectId}`); // 订阅新Store,同步数据给外部订阅者 unsubscribeCurrentStore = currentStore.subscribe(run, invalidate); }); } // 如果已有活跃Store,直接订阅它 if (currentStore) { return currentStore.subscribe(run, invalidate); } // 清理函数:页面卸载时取消所有内部订阅 return () => { unsubscribePage?.(); unsubscribeCurrentStore?.(); }; } // 代理set方法到当前活跃的Store function set(data) { currentStore?.set(data); } // 代理update方法到当前活跃的Store function update(updater) { currentStore?.update(updater); } return { subscribe, set, update }; } // 导出单例Store供组件复用 export const projectStore = createProjectStore();
2. 组件中使用
和使用普通realtimeStore完全一致,既可以通过$projectStore访问数据,也能直接调用set/update修改:
<script> import { projectStore } from './stores'; function updateProjectName() { projectStore.set({ ...$projectStore, name: 'Updated Project Name' }); } </script> <div>当前项目名称:{$projectStore?.name}</div> <button on:click={updateProjectName}>修改名称</button>
关键细节说明
- 动态切换Store:当
$page.params.projectId变化时,自动销毁旧的realtimeStore实例并创建新的,确保数据路径始终和当前项目ID匹配。 - 接口一致性:对外暴露的
subscribe/set/update方法和原生realtimeStore完全一致,组件无需修改原有逻辑。 - 内存泄漏防护:订阅返回的清理函数会自动取消内部的
page订阅和旧Store订阅,避免内存泄漏。 - 容错处理:调用
set/update时通过可选链?.判断currentStore是否存在,避免页面加载初期projectId未就绪时的报错。
内容的提问来源于stack exchange,提问作者Nikolay Dyankov
相关产品推荐
相关产品推荐

