如何让回调中从Store获取的modal具备响应式特性?
问题
我尝试让回调中返回的modal具备响应式特性,是否有可行方案?例如当我调用modal.isOpen = false时,state数组中的底层模型并未更新。
原代码
Store:
const store = () => { const state = []; const { subscribe, set, update } = writable(state) const openModal(data) { const modal = { isOpen: false, loading: false, onConfirm: data.onConfirm } return [...state, modal] } return { subscribe, set, update, openModal } }
Modal 组件:
{#each $modals as modal, i (modal)} <Modal bind:open={$modals[i].isOpen}> <Button on:click={() => $modals[i].onConfirm($modals[i])} bind:loading={$modals[i].loading}> Close </Button> </Modal> {/each}
调用组件:
store.openModel({ onConfirm: async ($modal) => { $modal.loading = true await doSomething() $modal.loading = false $modal.isOpen = false } })
解决方案
核心问题
直接修改数组内对象的属性(比如$modal.isOpen = false)不会触发Svelte store的响应式更新,因为writable store仅在通过set/update方法修改整个state引用时才会通知订阅者,直接修改对象属性不会改变数组的引用,store无法感知变化。
基础修复方案
1. 修正Store的openModal方法
原方法只是返回新数组但未更新store状态,需要改用update方法触发store更新:
const store = () => { const state = []; const { subscribe, set, update } = writable(state) const openModal(data) { update(currentState => { const modal = { isOpen: true, // 符合openModal语义,默认打开弹窗 loading: false, onConfirm: data.onConfirm } return [...currentState, modal] }) } return { subscribe, set, update, openModal } }
2. 修改回调逻辑,通过store更新状态
不要直接修改modal对象,而是通过update方法生成新数组副本,修改对应索引的modal属性:
{#each $modals as modal, i (modal)} <Modal bind:open={$modals[i].isOpen}> <Button on:click={() => $modals[i].onConfirm(i)} <!-- 传递弹窗索引 --> bind:loading={$modals[i].loading}> Close </Button> </Modal> {/each}
store.openModal({ onConfirm: async (modalIndex) => { // 更新loading状态 store.update(modals => { const updatedModals = [...modals]; updatedModals[modalIndex].loading = true; return updatedModals; }); await doSomething(); // 重置loading并关闭弹窗 store.update(modals => { const updatedModals = [...modals]; updatedModals[modalIndex].loading = false; updatedModals[modalIndex].isOpen = false; return updatedModals; }); } })
进阶方案:单个Modal独立Store
如果需要更细粒度的响应式控制,可以将每个modal包装成独立的writable store,修改单个modal属性时无需更新整个数组:
const store = () => { const state = []; const { subscribe, set, update } = writable(state) const openModal(data) { const modalStore = writable({ isOpen: true, loading: false, onConfirm: data.onConfirm }); update(currentState => [...currentState, modalStore]); return modalStore; } return { subscribe, set, update, openModal } }
Modal组件调整为:
{#each $modals as modalStore, i (modalStore)} <Modal bind:open={$modalStore.isOpen}> <Button on:click={() => $modalStore.onConfirm($modalStore)} bind:loading={$modalStore.loading}> Close </Button> </Modal> {/each}
调用时可直接修改modal状态:
const modalStore = store.openModal({ onConfirm: async ($modal) => { $modal.loading = true; await doSomething(); $modal.loading = false; $modal.isOpen = false; } });
内容的提问来源于stack exchange,提问作者digout
相关产品推荐
相关产品推荐

