自定义Svelte Store结合Immer重复刷新及数据绑定失效问题
Svelte Immer自定义Store问题修复
问题1:未变更数据仍触发订阅刷新
原因
- 原
producer方法直接调用store.update,即便Immer返回原对象(无修改操作时),store.update仍会触发订阅回调 - 自定义
set方法依赖闭包保存的初始value,而非store的实时最新状态,导致新旧值对比逻辑失效
修复方案
在immerWritable内部维护当前状态的实时引用,所有更新操作先通过Immer生成新值,仅当新值与当前状态不同时才触发store更新,避免无意义的订阅刷新。
问题2:数据绑定失效
原因
- 开启
immutable={true}后,Svelte不会检测对象内部属性的变化,直接绑定$store.sub.a无法触发store状态更新 - 原
update方法依赖闭包的初始value,无法获取store最新状态,导致更新逻辑错误
修复方案
使用本地变量中转绑定值,通过事件触发store的immutable更新(推荐,符合immutable设计原则);也可关闭immutable选项(不推荐,会增加Svelte的深度检测开销)。
修改后的自定义Store代码
import { writable } from "svelte/store"; import produce from "immer"; const immerWritable = (initialValue) => { const store = writable(initialValue); // 实时同步当前状态,避免依赖闭包初始值 let currentValue = initialValue; const internalUnsubscribe = store.subscribe(value => { currentValue = value; }); function set(newValue) { // 仅当值真正变化时更新store if (newValue !== currentValue) { store.set(currentValue = newValue); } } const producer = (fn) => { const newValue = produce(currentValue, fn); set(newValue); }; const update = (fn) => { const newValue = produce(currentValue, fn); set(newValue); }; // 清理内部订阅,避免内存泄漏 function destroy() { internalUnsubscribe(); } return { producer, set, update, subscribe: store.subscribe, destroy }; }; const store = immerWritable({ sub: { a: 1, b: 2 }, sub2: { a: 1, b: 2 } }); const actions = { setSubA_10: () => store.producer((draft) => { draft.sub.a = 10; }) }; export default { ...store, ...actions };
修改后的App.svelte代码
<script> import store from "./store"; import { onDestroy } from "svelte"; let changed = 0; // 本地变量中转绑定值,遵循immutable原则 let subA = $store.sub.a; const unsubscribe = store.subscribe(s => { changed++; // 同步本地变量与store状态 subA = s.sub.a; }); // 输入变化时通过Immer更新store const updateSubA = () => { store.producer(draft => { draft.sub.a = Number(subA); }); }; onDestroy(() => { unsubscribe(); store.destroy(); }); </script> <div>store changed {changed}</div> <button on:click={store.setSubA_10}>set sub.a to 10</button> <input bind:value={subA} type="number" on:input={updateSubA}/>
内容的提问来源于stack exchange,提问作者Sami Al-Subhi
相关产品推荐
相关产品推荐

