更改路由时模型挂钩中的无限重新验证错误(Ember.js)

lpwwtiir  于 2022-10-20  发布在  其他
关注(0)|答案(1)|浏览(170)

我有一个RPG制作系统的申请。我有一条路线用于用户的当前库存(库存路线),另一条路线供用户收集物品并最终将其放入库存(这称为收集路线)。每当我从Inventory路线导航到Gather路线或反之亦然时,我都会看到此错误。这似乎与我在收集路线的模型挂钩中加载的项目模型有关:

> Uncaught (in promise) Error: Assertion Failed: You attempted to update
> `length` on `item:common_curative_reagent
> (@ember-data:lid-item-common_curative_reagent),item:common_poisonous_reagent
> (@ember-data:lid-item-common_poisonous_reagent),(...)`, but it had
> already been used previously in the same computation.  Attempting to
> update a value after using it in a computation can cause logical
> errors, infinite revalidation bugs, and performance issues, and is not
> supported.

`length` was first used:

Stack trace for the update:
    at dirtyTagFor (validator.js:575)
    at markObjectAsDirty (index.js:546)
    at notifyPropertyChange (index.js:584)
    at arrayContentDidChange (index.js:691)
    at replaceInNativeArray (index.js:759)
    at Array.replace (array.js:1730)
    at Array.pushObjects (array.js:1452)

从我对无限重新验证错误的研究来看,我认为这与Glimmer跟踪属性在同一计算中被引用有关,也可以修改它。在这种情况下,跟踪属性似乎是我在Gather路由中加载的项目列表(用户可以收集的项目列表),但这个列表必须存在于我无法访问的框架中?
库存模型挂钩:

async model()
{
    let user = this.session.getUser();
    let inventory = await this.inventory.getInventory();

    if (isEmpty(inventory?.ingredients)) { return []; }

    let items = RSVP.all(Object.entries(inventory.ingredients).map(([itemID]) => { return this.store.findRecord('item', itemID) }));

    let model = RSVP.hash({
        "items": items,
        "user": user,
        "inventory": inventory
    });

    return model;
}

这个错误似乎与下面的代码有关,因为如果我将其注解掉并返回空列表,则不会发生这种情况。收集模型挂钩:

async loadGatherItems(gatherAry)
{
    // Search through the gather table columns and get a list of all possible items
    let promises = [];
    gatherAry.toArray().forEach((gatherRecord) =>
    {
        if (isEmpty(gatherRecord?.items)) { return; }
        gatherRecord.items.forEach((itemGroup) =>
        {
            if (isEmpty(itemGroup?.item)) { return; }
            let itemID = itemGroup.item;
            promises.push(this.store.findRecord("item", itemID));
        });
    });

    let gatherItems = await RSVP.all(promises);

    // Also include any 'trivial' item
    let trivials = await this.store.query("item", {
            "orderBy": "rarity",
            "equalTo": 'trivial'
        });
    trivials.forEach((item) => { gatherItems.push(item); });

    return gatherItems;
}

尽管出现了错误,但应用程序本身似乎运行良好。正如我所说的,当我分别加载Inventory或Gather路由时不会发生这种情况,但只有当我从一个切换到另一个时才会发生。它只发生一次(例如,如果我不断来回切换,我只会看到一次错误)。
如果在这两个路由之间切换之前加载Items路由,则不会发生错误…Items路由在Item模型上执行findAll。事实上,如果我在库存路线的顶部添加一个findAll,错误就不会发生。不过,我不想保留这一点,因为我不需要在库存路线中加载所有可能的物品——我只需要库存中的物品。
我仍然在学习Ember和JS,所以如果能帮助解释为什么会发生这种情况,我将不胜感激!

编辑1

我仍然不知道为什么会发生这个错误,但这肯定与我将Items加载到商店的方式有关。当我切换路线时,使用findRecord获得的任何项目都会导致出现错误-如果该项目已经在商店中,则不会导致出现错误。这就是为什么在我的模型挂钩顶部执行findAll会导致错误消失的原因。

qhhrdooz

qhhrdooz1#

最终,错误来自对多个尚未加载到存储中的ID调用findRecord。与其在循环中调用findRecord,我应该尝试进行某种单一网络查询,以获得尽可能小的包含列表,然后在客户端对其进行精简。
我不知道这方面的最佳实践,也不知道为什么会发生错误(或者是否应该发生错误?)。一方面,我试图通过只请求我知道我需要的ID来限制从服务器返回的数据量。另一方面,我正在权衡较小的数据集大小和更多的请求数量。
也许这只是我后端的一个限制,它不支持对一组特定ID(firebase)的查询。

相关问题