Svelte:如何从依赖其他store的函数返回的store创建派生store
解决方案
你遇到的核心是嵌套Store场景:派生返回的值不是普通状态,而是另一个Store,需要将两层Store打平为一层即可解决。
方案1:通用打平工具函数(推荐,无内存泄漏,可复用)
先实现一个10行左右的通用工具,专门处理外层Store值为内层Store的场景,自动完成订阅、销毁、状态同步:
import { writable } from 'svelte/store'; function switchStore(outerStore) { const innerStore = writable(undefined, () => { let innerUnsubscribe; // 订阅外层Store,值变化时切换内层Store const outerUnsubscribe = outerStore.subscribe(outerValue => { if (innerUnsubscribe) innerUnsubscribe(); innerUnsubscribe = outerValue.subscribe(innerValue => innerStore.set(innerValue)); }); // 总销毁逻辑 return () => { outerUnsubscribe(); if (innerUnsubscribe) innerUnsubscribe(); }; }); return innerStore; }
业务代码调用方式:
import { derived } from 'svelte/store'; const groupId = getGroupId(); // 外层派生Store,值为query返回的Store const resultOuter = derived(groupId, $groupId => query(`all users in group ${$groupId}`)); // 打平为单层Store,groupId变化时自动销毁旧查询、订阅新查询 const result = switchStore(resultOuter); // 原有派生逻辑完全不需要修改 const userAvatars = derived(result, $result => { /* 原有逻辑 */ });
方案2:响应式块全量更新(适合简单场景,无额外工具)
如果不想封装工具,也可以将userAvatars的声明也放入响应式块,保证每次查询更新时派生Store同步重建,注意手动处理旧Store的销毁避免内存泄漏:
import { derived } from 'svelte/store'; const groupId = getGroupId(); let result, userAvatars, unsubOldQuery; $: { // 销毁旧的查询Store if (unsubOldQuery) unsubOldQuery(); // 生成新查询 result = query(`all users in group ${$groupId}`); unsubOldQuery = result.subscribe(() => {}); // 重建派生Store userAvatars = derived(result, $result => { /* 原有逻辑 */ }); }
Svelte 5 简化方案
如果你使用Svelte 5的Runes特性,不需要额外封装,直接利用Runes的自动Store解包能力即可:
const groupId = getGroupId(); const result = $derived(query(`all users in group ${$groupId}`)); const userAvatars = $derived($result.map(user => user.avatar));
内容的提问来源于stack exchange,提问作者Tomáš M.
相关产品推荐
相关产品推荐

