Svelte可写Store未触发更新通知问题咨询
Svelte Store 更新不触发响应式语句的问题分析与解决
问题现象
基于对象结构创建Svelte writable store后,组件中通过bind:value直接绑定store对象内部的name属性:输入内容时,依赖$data的响应式语句$: console.log($data)不会触发;但点击保存按钮时,能看到store数据已正确更新。
核心原因
Svelte的writable store仅在调用set或update方法、且触发引用变更(或明确通知订阅者)时,才会向所有订阅者发送更新通知。
当前场景中,bind:value={d.name}是直接修改了store对象内部的属性——由于对象是引用类型,数据确实会同步变化,但这个操作完全绕过了store的set/update方法,store没有感知到变化,自然不会触发订阅更新,也就不会执行依赖$data的响应式语句。
而删除按钮的remove方法通过update修改了store对象(删除属性后返回原对象),Svelte的update会强制触发一次订阅通知,所以删除操作会触发console.log。
解决方案
方案1:通过store方法更新属性
不要直接绑定对象内部属性,而是通过自定义的store方法修改值,确保触发store的更新通知:
修改store代码,添加updateName方法:
import { writable } from "svelte/store"; function createData() { const { subscribe, set, update } = writable({ "1": { name: "" }, "2": { name: "" }, "3": { name: "" }, }); return { subscribe, set, update, remove: (i) => update(n => { delete n[i]; return n; }), // 新增更新name的方法,返回新对象确保引用变更 updateName: (key, newName) => update(n => { return { ...n, [key]: { ...n[key], name: newName } }; }) }; } export const data = createData();
组件中修改绑定逻辑,通过input事件调用store方法:
<script> import { data } from "./store.js"; $: console.log($data) function save() { console.log($data); } </script> <div> <children> {#each Object.entries($data) as [key, d]} <child> {key} <input type="text" value={d.name} on:input={(e) => data.updateName(key, e.target.value)} /> <button on:click={() => data.remove(key)}>delete</button> </child> {/each} </children> <button on:click={save}>Save</button> </div>
方案2:改用数组存储数据
如你猜测的,改用数组存储元素,每次修改时通过set或update返回新数组,确保引用变更触发更新:
store代码示例:
import { writable } from "svelte/store"; function createData() { const { subscribe, set, update } = writable([ { id: "1", name: "" }, { id: "2", name: "" }, { id: "3", name: "" }, ]); return { subscribe, set, update, remove: (id) => update(items => items.filter(item => item.id !== id)), updateName: (id, newName) => update(items => items.map(item => item.id === id ? { ...item, name: newName } : item) ) }; } export const data = createData();
组件中遍历数组:
<script> import { data } from "./store.js"; $: console.log($data) function save() { console.log($data); } </script> <div> <children> {#each $data as item} <child> {item.id} <input type="text" value={item.name} on:input={(e) => data.updateName(item.id, e.target.value)} /> <button on:click={() => data.remove(item.id)}>delete</button> </child> {/each} </children> <button on:click={save}>Save</button> </div>
内容的提问来源于stack exchange,提问作者Stefan Stoychev
相关产品推荐
相关产品推荐

