You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何构建含自定义方法的复杂响应式库存对象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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 14:38:21