如何构建含自定义方法的复杂响应式库存对象Store?
Svelte 库存响应式 Store 问题与解决方案
问题背景
原始库存对象结构:
const inventory = { maxSlots: 24, content: [ {id: "item_01", quantity: 5, slotId: 0}, {id: "item_02", quantity: 2, slotId: 2}, {id: "item_03", quantity: 1, slotId: 6}, ] };
需要实现的自定义方法:
inventory.getRemainingSlots()inventory.getFirstFreeSlotid()inventory.addItem()(依赖inventory.getFirstFreeSlotid())
可选响应式方案:
- 单一writable
- 含
get、set、update和subscribe方法的自定义Store - 结合writable的类实例
- 为每个单独属性创建writable,再构建Store的Store
当前已实现的inventoryStore.js代码存在问题:getContent方法无法在.svelte文件中调用。
function createStore() { const { subscribe, set, update } = writable({ maxSlots: 8, content: [ { id: "item_01", quantity: 5, slotId: 0 }, { id: "item_02", quantity: 2, slotId: 2 }, { id: "item_03", quantity: 1, slotId: 6 }, ], }); return { // Store methods subscribe, set, update, get: () => get({ subscribe }), // Custom methods getContent: () => { // I can't use this in .svelte files return inventoryStore.get().content; }, getFirstFreeSlotId: () => { const content = inventoryStore.get().content; const maxSlots = inventoryStore.get().inventoryMaxSlots; for (let _slotId = 0; _slotId < maxSlots; _slotId++) { const foundItem = content.find(_x => _x.slotId === _slotId); if (!foundItem?.id) { return _slotId; } } return -1; } }; } export const inventoryStore = createStore();
解决方案
1. 修复自定义方法的核心问题
问题根源是getContent和getFirstFreeSlotId中直接引用了未完成初始化的inventoryStore变量。我们可以在createStore内部定义一个获取状态的辅助函数,避免外部依赖:
import { writable, get } from 'svelte/store'; function createStore() { const { subscribe, set, update } = writable({ maxSlots: 8, content: [ { id: "item_01", quantity: 5, slotId: 0 }, { id: "item_02", quantity: 2, slotId: 2 }, { id: "item_03", quantity: 1, slotId: 6 }, ], }); // 内部状态获取函数,避免引用未初始化的外部store const getState = () => get({ subscribe }); return { // 基础Store方法 subscribe, set, update, get: getState, // 自定义方法实现 getContent: () => getState().content, getFirstFreeSlotId: () => { const { content, maxSlots } = getState(); for (let slotId = 0; slotId < maxSlots; slotId++) { if (!content.find(item => item.slotId === slotId)) { return slotId; } } return -1; }, getRemainingSlots: () => { const { content, maxSlots } = getState(); return maxSlots - content.length; }, addItem: (itemId) => { const freeSlotId = getFirstFreeSlotId(); if (freeSlotId === -1) return false; update(state => { state.content.push({ id: itemId, quantity: 1, slotId: freeSlotId }); return state; }); return true; } }; } export const inventoryStore = createStore();
同时修正了getFirstFreeSlotId中的拼写错误(inventoryMaxSlots改为maxSlots),并补充了需求中的getRemainingSlots和addItem方法。
2. 在Svelte组件中使用Store
修复后即可在.svelte文件中正常调用所有自定义方法,若需要自动响应状态变化,可结合$语法实现:
<script> import { inventoryStore } from './inventoryStore.js'; // 自动响应Store变化 $: content = inventoryStore.getContent(); $: freeSlotId = inventoryStore.getFirstFreeSlotId(); $: remainingSlots = inventoryStore.getRemainingSlots(); const handleAddItem = () => { inventoryStore.addItem(`item_${Date.now()}`); }; </script> <div> <p>剩余空位:{remainingSlots}</p> <p>首个空位ID:{freeSlotId}</p> <button on:click={handleAddItem}>添加随机物品</button> <h3>库存列表</h3> <ul> {#each content as item} <li>Slot {item.slotId}: {item.id} × {item.quantity}</li> {/each} </ul> </div>
3. 响应式方案选型建议
- 自定义Store(推荐):当前采用的方案,将状态与操作逻辑封装在一起,符合Svelte Store设计思路,结构清晰易维护。
- 类实例封装:适合面向对象编程习惯,内部用writable管理状态,逻辑更内聚:
import { writable, get } from 'svelte/store'; export class Inventory { #store; constructor(initialState) { this.#store = writable(initialState); } subscribe(callback) { return this.#store.subscribe(callback); } get state() { return get(this.#store); } getRemainingSlots() { return this.state.maxSlots - this.state.content.length; } getFirstFreeSlotId() { const { content, maxSlots } = this.state; for (let slotId = 0; slotId < maxSlots; slotId++) { if (!content.find(item => item.slotId === slotId)) { return slotId; } } return -1; } addItem(itemId) { const freeSlot = this.getFirstFreeSlotId(); if (freeSlot === -1) return false; this.#store.update(state => { state.content.push({ id: itemId, quantity: 1, slotId: freeSlot }); return state; }); return true; } } export const inventoryStore = new Inventory({ maxSlots: 8, content: [ { id: "item_01", quantity: 5, slotId: 0 }, { id: "item_02", quantity: 2, slotId: 2 }, { id: "item_03", quantity: 1, slotId: 6 }, ] }); - 拆分多writable:不推荐,库存的
maxSlots与content强关联,拆分后会增加状态同步复杂度。
内容的提问来源于stack exchange,提问作者Icaruk
相关产品推荐
相关产品推荐

