流星 - 我如何使这个"反应"使用Deps?

时间:2014-09-08 11:10:11

标签: javascript meteor

在我的客户端,我显示了一个用户列表和一个存储在数据库中的每个用户点的小图表(使用名为sparklines的jQuery插件)。

在Template.rendered方法

上绘制图表
// client/main.js
Template.listItem.rendered = function() {
    var arr = this.data.userPoints // user points is an array of integers
    $(this.find(".chart")).sparkline(arr);
}

现在我在服务器端有一个Meteor方法,定期调用它来更新用户点。

Meteor.methods({
    "getUserPoints" : function getUserPoints(id) {
        // access some API and fetch the latest user points
    }
});

现在,我希望每当调用Meteor方法时,图表都会自动更新。我在模板上有一个方法,并调用这个Meteor方法。

Template.listItem.events({
    "click a.fetchData": function(e) {
        e.preventDefault();
        Meteor.call("getUserPoints", this._id);
    }
});

如何将此代码转换为“被动”代码?

2 个答案:

答案 0 :(得分:15)

您需要将reactive data sourceSessionReactiveVar)与Tracker一起使用。

使用ReactiveVar:

if (Meteor.isClient) {
    Template.listItem.events({
        "click a.fetchData": function(e) {
            e.preventDefault();
            var instance = Template.instance();
            Meteor.call("getUserPoints", this._id, function(error, result) {
                instance.userPoints.set(result)
            });
        }
    });

    Template.listItem.created = function() {
      this.userPoints = new ReactiveVar([]);
    };

    Template.listItem.rendered = function() {
        var self = this;
        Tracker.autorun(function() {
            var arr = self.userPoints.get();
            $(self.find(".chart")).sparkline(arr);
        })
    }
}

使用会话:

if (Meteor.isClient) {
    Template.listItem.events({
        "click a.fetchData": function(e) {
            e.preventDefault();
            Meteor.call("getUserPoints", this._id, function(error, result) {
                Session.set("userPoints", result);
            });
        }
    });

    Template.listItem.rendered = function() {
        var self = this;
        Tracker.autorun(function() {
            var arr = Session.get("userPoints");
            $(self.find(".chart")).sparkline(arr);
        })
    }
}

这些实施之间的差异:

  

ReactiveVar类似于Session变量,只有少数几个   差异:

     

ReactiveVars没有全球名称,例如" foo"在   Session.get("富&#34)。相反,它们可以在本地创建和使用   附加到模板实例的示例,如:this.foo.get()。

     

ReactiveVars不会通过热代码推送自动迁移,   而会话状态是。

     

ReactiveVars可以保存任何值,而Session变量是有限的   到JSON或EJSON。

Source

Deps已弃用,但仍可使用。

答案 1 :(得分:7)

最容易扩展的解决方案是将数据存储在local collection中 - 通过传递一个空名称,该集合将是本地和会话,因此您可以将所需内容放入其中并仍然实现所有反应的好处。如果将getUserPoints的结果插入到此集合中,则可以编写一个帮助程序来为每个用户获取适当的值,它将自动更新。

userData = new Meteor.Collection(null);

// whenever you need to call "getUserPoints" use:
Meteor.call("getUserPoints", this._id, function(err, res) {
    userData.upsert({userId: this._id}, {$set: {userId: this._id, points: res}});
});

Template.listItem.helpers({
    userPoints: function() {
        var pointsDoc = userData.findOne({userId: this._id});
        return pointsDoc && pointsDoc.points;
    }
});

使用Tracker软件包(以前称为Deps)有一种替代方法,可以在这里快速实现,但需要进行扩展。从本质上讲,您可以设置新的Tracker.Dependency来跟踪用户点的变化:

var pointsDep = new Tracker.Dependency();

// whenever you call "getUserPoints":
Meteor.call("getUserPoints", this._id, function(err, res) {
    ...
    pointsDep.changed();
});

然后只需在listItem模板中添加一个虚拟帮助器(即一个没有按设计返回任何内容的帮助器):

<template name="listItem">
    ...
    {{pointsCheck}}
</template>

Template.listItem.helpers({
    pointsCheck: function() {
        pointsDep.depend();
    }
});

虽然它不会返回任何内容,但它会强制模板在调用pointsDep.changed()时重新呈现(当收到新用户点数据时)。