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

eri*_*bae 7 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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

Kub*_*bek 15

您需要与Tracker一起使用reactive data source(Session,ReactiveVar).

使用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);
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

使用会话:

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);
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

这些实施之间的区别:

ReactiveVar类似于Session变量,但有一些差异:

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

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

ReactiveVars可以包含任何值,而Session变量仅限于JSON或EJSON.

资源

Deps已弃用,但仍可使用.


ric*_*ilv 7

最容易扩展的解决方案是将数据存储在本地集合中 - 通过传递一个空名称,该集合将是本地和会话,因此您可以将所需内容放入其中并仍然可以实现反应的所有好处.如果将结果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;
    }
});
Run Code Online (Sandbox Code Playgroud)

还有一种使用Tracker软件包(以前称为Deps)的替代方法,这种方法可以在这里快速实现,但可以随意扩展.从本质上讲,您可以设置一个新Tracker.Dependency的跟踪用户点的更改:

var pointsDep = new Tracker.Dependency();

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

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

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

Template.listItem.helpers({
    pointsCheck: function() {
        pointsDep.depend();
    }
});
Run Code Online (Sandbox Code Playgroud)

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