使用 jQuery 计算 Mobx 4 中的“this”值

问题描述 投票:0回答:1

这是我第一次使用Mobx,我试图了解它是如何应用于我的项目(不是React基础,只是使用jquery更新DOM)。 我从 Mobx 4 开始(我需要支持旧浏览器,所以我不使用最新版本 6 ),并按照 here 的示例进行操作,但它使用了 Mobx 2 版本。 当与 Mobx 4 一起使用时,它会抛出一个错误:

function ShoppingCart() {
    mobx.extendObservable(this, {
        entries: [],
        total: function() {
            return this.entries.reduce(function (sum, entry) {
                return sum + entry.price;
            }, 0);
        }

    });
}

控制台显示:

mobx] Encountered an uncaught exception that was thrown by a reaction or observer component, in: 'Reaction[Autorun@19]' TypeError: Cannot read properties of undefined (reading 'reduce')

我尝试使用这样的匿名函数:

function ShoppingCart() {
    mobx.extendObservable(this, {
        entries: [],
        total: () => {
            return this.entries.reduce(function (sum, entry) {
                return sum + entry.price;
            }, 0);
        }

    });
}

但是它返回了这样的函数声明:

0function () { return this.article ? this.article.price * this.amount : 0; }

我想知道这里有什么区别?在这种情况下 Mobx 如何处理 this(.entries) ? 为什么这个计算无法获取条目的值?谢谢!

这是jsfiddle中项目的链接:

或者我的全部来源:

/** Data model */
function Article(name, price) {
    mobx.extendObservable(this, {
        name: name,
        price: price
    });
}

function ShoppingCartEntry(article) {
    mobx.extendObservable(this, {
        article: article,
        amount: 1,
        price: function () {
            return this.article ? this.article.price * this.amount : 0;
        }
    });
}

function ShoppingCart() {
    mobx.extendObservable(this, {
        entries: [],
        total: function () {
            return this.entries.reduce(function (sum, entry) {
                return sum + entry.price;
            }, 0);
        }

    });
}

$(function () {

// Some available articles
    var articles = mobx.observable([
        ["Funny Bunnies", 17.63],
        ["Awesome React", 23.95],
        ["Second hand netbook", 50.00]
    ].map(function (e) {
        return new Article(e[0], e[1]);
    }));

// Our shopping cart
    var shoppingCart = new ShoppingCart();
// With a demo item inside
    shoppingCart.entries.push(new ShoppingCartEntry(articles[0]));

    $.fn.insertAt = function (index, $parent) {
        return this.each(function () {
            if (index === 0) {
                $parent.prepend(this);
            } else {
                $parent.children().eq(index - 1).after(this);
            }
        });
    };

    /** UI Logic */
    var $articles = $("#articles");

// Make the articles list follow the array
    articles.observe(function (change) {
        console.log(change);
        // items where added or removed
        if (change.type === "splice") {
            $articles.children().slice(change.index, change.index + change.removed.length).remove();
            for (var i = 0; i < change.addedCount; i++) {
                renderArticle(articles[change.index + i])
                    .insertAt(change.index + i, $articles);
            }
        }
    }, true); // true makes sure the observe function is invoked immediately

// Render an article in the articles overview, and watch or changes
    function renderArticle(article) {
        var $name = $("<span>").text(article.name);
        var $price = $("<span>").addClass("price").text(article.price);
        mobx.autorun(function () {
            $name.text(article.name);
        });
        mobx.autorun(function () {
            $price.text(article.price);
        });
        return $("<li>").append($name,
            $("<button>").text("+").addClass("add-article"),
            $("<button>").text("edit").addClass("edit-article"),
            $price);
    }

// ShoppingCart ui
    var $cart = $("#cart");
    var $total = $("#total");

    mobx.autorun(function () {
        // console.log(shoppingCart, shoppingCart.total, shoppingCart.entries);
        $total.text(shoppingCart.total);
    }, true);

    shoppingCart.entries.observe(function (change) {
        // items where added or removed
        if (change.type === "splice") {
            $cart.children().slice(change.index, change.index + change.removed.length).remove();
            for (var i = 0; i < change.addedCount; i++) {
                renderCartEntry(shoppingCart.entries[change.index + i])
                    .insertAt(change.index + i, $cart);
            }
        }
    }, true);

    function renderCartEntry(entry) {
        var $name = $("<span>").text(entry.article.name);
        var $amount = $("<span>").addClass("price").text(entry.amount);
        mobx.autorun(function () {
            $name.text(entry.article.name);
        });
        mobx.autorun(function () {
            $amount.text(entry.amount);
        });
        return $("<li>").append(
            $("<button>").text("-").addClass("remove-article"),
            $name,
            $amount);
    }


// Events
    $("#new-article").on("click", function () {
        articles.push(new Article(prompt("Article name"), prompt("Price")));
    });

    $(document).on("click", ".edit-article", function (event) {
        var idx = $(event.target).parent().index();
        articles[idx].name = prompt("New name");
        articles[idx].price = prompt("New price");
    });

    $(document).on("click", ".add-article", function (event) {
        var article = articles[$(event.target).parent().index()];
        var existingEntry = shoppingCart.entries.find(function (entry) {
            return entry.article === article;
        });
        if (existingEntry)
            existingEntry.amount += 1;
        else
            shoppingCart.entries.unshift(new ShoppingCartEntry(article));
    });

    $(document).on("click", ".remove-article", function (event) {
        var entryIndex = $(event.target).parent().index();
        if ((shoppingCart.entries[entryIndex].amount -= 1) < 1)
            shoppingCart.entries.splice(entryIndex, 1);
    });
})
jquery mobx
1个回答
0
投票

我找到了答案。就像@phuzi 的建议。这就是 JS 中的

this
。我错误地接受了 Mobx 使用示例而不怀疑
this
的价值。正确的
ShoppingCartEntry
函数应该是这样的:

function ShoppingCartEntry(article) {
    mobx.extendObservable(this, {
        article: article,
        amount: 1,
        price: () => {
            return this.article ? this.article.price * this.amount : 0;
        }
    });
}

我使用箭头函数来表示价格,所以

this
现在将是
ShoppingCartEntry
。 然后我们需要将
ShoppingCart
更新为:

function ShoppingCart() {
    mobx.extendObservable(this, {
        entries: [],
        total: () => {
            return this.entries.reduce(function (sum, entry) {
                return sum + entry.price();
            }, 0);
        }
    });
}

与 Mobx v2 的示例相比,

entry.price
必须作为函数调用。 或者我们可以像这样更新
ShoppingCartEntry
以使用价格的 getter 让
entry.price
与之前相同:

class ShoppingCartEntry {
    article;

    constructor(article) {
        this.article = article;
        mobx.extendObservable(this, {
            article: article,
            amount: 1,
        });
    }

    get price() {
        return this.article ? this.article.price * this.amount : 0;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.