【问题标题】:Meteor - how do I make this "reactive" using Deps?Meteor - 我如何使用 Deps 使这个“反应性”?
【发布时间】:2015-04-18 20:17:09
【问题描述】:

在我的客户端,我显示了一个用户列表和每个用户在数据库中的积分的小图表(使用名为 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);
    }
});

如何将此代码转换为“反应式”代码?

【问题讨论】:

  • Meteor 核心开发者 Sashko Stubailo 最近为reactive methods 发布了一个包。

标签: javascript meteor


【解决方案1】:

您需要将reactive data source (Session, ReactiveVar) 与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 变量,有一些 区别:

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

ReactiveVar 不会跨热代码推送自动迁移, 而会话状态是。

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

Source

Deps 已弃用,但仍可使用。

【讨论】:

  • 不使用 Sessions 怎么办?单个页面上可能有很多“用户”视图...
【解决方案2】:

最容易扩展的解决方案是将数据存储在 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() 时强制模板重新呈现(这将是在接收到新的用户点数据时)。

【讨论】:

  • 不错!我不知道将集合设置为仅限本地!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-25
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-10
  • 1970-01-01
相关资源
最近更新 更多