【问题标题】:Meteor: using Sessions and ReactiveVarMeteor:使用 Sessions 和 ReactiveVar
【发布时间】:2015-10-05 03:26:48
【问题描述】:

什么时候应该使用SessionReactiveVar?我使用Session 变量作为组件之间的通信媒介。我们以 Stackoverflow 为例。

我标记了三个假设的组件。让我们看一下filters 组件。如果您单击Tags,则Main 组件将根据您喜欢的标签显示其问题。为此,我将在单击Tags 按钮时设置Session.set("Main/showTags", true)。在 Main 组件中,我将有一个如下所示的辅助函数:

Template.Main.helpers({
  posts: function() {
    var isTags = Session.get("Main/showTags");
    var isQuestions = Session.get("Main/showQuestions");
    ...
    if (isTags) {
      return Posts.find().sort({tags: 1}) // or something along the lines
    } else if (isQuestions) ...
  }
});

这在大多数情况下运行良好,但我从很多地方看到我应该避免使用Session 并使用ReactiveVar。但是如果我在任何地方都使用ReactiveVar,那么我需要对所有模板实例的引用。我希望它在直接父模板和子模板之间运行良好(例如,在主组件内部,可能有VoteAnswerViewsButtonTemplate)但是当您希望独立组件相互通信时,您将如何使用ReactiveVar

这是我的最后一个问题。如何适当地使用SessionReactiveVar 来保持组件的范围并使它们也相互通信?另外,如果我像现在这样使用Session,是否会不必要地污染全局命名空间?

相关文件:

  1. https://dweldon.silvrback.com/scoped-reactivity
  2. https://www.discovermeteor.com/blog/reactivity-basics-meteors-magic-demystified/

【问题讨论】:

  • Session 可以从客户端销毁。所以我假设这不是你想用于页面导航的东西。
  • 我同意@KawsarAhmed,我发现有一个自定义 url 更好,即使它只是用于过滤集,所以我可能会使用嵌套模板

标签: meteor


【解决方案1】:

据我所知,没有与 Session 变量相关的内置功能将它们与您将在 @ 中声明的常规反应式字典全局变量(如 @Kyll 声明)区分开来987654326@ 文件。唯一的区别是Session 必须在应用程序范围内访问的“限制”。

当我在较小的范围内使用reactive dictionaryreactive variables 时,我很高兴能够利用这种差异。我认为我有三种范围:

1 - 全球范围。例如。当前的 UI 语言,UI 皮肤。我为此使用Session。简单的全局数据,不会与其他任何东西混淆。

2 - 一组模板。 例如,假设我创建了一个页面来在我的应用程序中生成和自定义 pdf。我不会在其他地方重用任何组件。我的集群是一个包含三个文件的文件夹,我们称它们为pdfgenerator.htmlpdfgenerator.jspdfgenerator_controller.js

我使用pdfgenerator_controller.js 来扩展所有细节的路线。

pdfgenerator.js 文件中,我有几个模板都在集群中使用。在文件的开头,我创建了一个反应式字典pageSession(类似于反应式变量),并在我的所有集群中使用它。它允许我在所有组件之间传递数据。

3 - 本地范围。 无论是单个模板还是可重用组件,它都意味着单独工作。我也不会为那些使用 Session vars。我不想过度拥挤Session 命名空间。我所做的是将在实例化过程中操作它所需的所有数据传递给我的模板。

可能来自空格键:

{{> mySingleTemplate data=myData}}

或使用 Javascript:

Blaze.renderWithData(Template.mySingleTemplate , myData, self.firstNode);

在本地范围的情况下,我还使用reactive dictionaryreactive vars 来处理单个模板中发生的反应。在这种情况下,我会尽量避免需要将数据被动返回到父模板的情况。如果我必须(即我可能不会用它制作一个包),我会使用在父模板范围内声明为全局的本地 minimongo 集合。这样,我可以将信息从可重用组件传递给它的父组件。

示例:上传模板。我使用 minimongo 来存储每个上传文件的名称、大小、类型、状态和 url。 minimongo 集合在父表单模板和子上传器模板之间共享。


底线:我只将Session 变量用于基本和全局信息。如果我需要全局共享的数据结构太复杂/太大,我就依赖一个集合。

我很想知道我是否做对了,所以这更像是一个答案,而不是一个测试,看看人们是否同意我的做事方式。欢迎所有的 cmets 和建议。

【讨论】:

  • 对于第三种情况,本地作用域,如何允许子模板访问其父模板的本地反应变量?
  • 4种可能:1)不是第三种情况,而是第二种情况:局部反应变量被设计共享 | 2)如果我只在实例化期间需要这些数据,我只需将它们传递给我的模板调用(见答案)| 3) 如果我需要定期访问它们,我将它们附加到父模板数据上下文(this.myVar = new Reactive-Var('foo'); 其中this 是父模板实例)。然后我使用Template.parentData().myVar.get() 访问它们。事实上,我从来没有这样做过。 | 4) 数据足够复杂,让我依赖父级中声明的 minimongo 本地集合
  • 我还有一个问题。参考您的原始答案,您是否在所有模板之外的 if (Meteor.isClient) 块中声明反应变量,以便所有模板都可以访问它,对吗?如果我说您不尝试将其附加到模板实例,我是对的吗?换句话说,你会这样做吗? pastebin.com/6LiLzjHq
  • 是的,我这样做。唯一的区别是,由于我使用的是位于client/views 文件夹中的文件,因此我不需要指定Meteor.isClient。如果我所有的模板都在同一个文件中,那么将它附加到模板实例似乎是一个不需要的约束。但是,如果它们不是,那是有道理的(参见上面的案例 3)。
【解决方案2】:

会话变量名声不好。事实是,在您的应用程序变大之前,它们都很好。在以下情况下,您会知道什么时候该离开 Session var:

  • 您不能保持 var 名称直截了当(例如 wtf isColumnHidden 又是什么意思?)或者,会话 var 形成自然集群(3 个会话 var 用于工具提示,5 个用于标签等)。
  • 您希望 url 中包含会话信息,这样您就可以向某人发送链接,他们会看到您看到的内容

那么,你如何解决每个问题?

  • 对于第一个示例,创建一个包。例如,在我的一个较大的项目中,我创建了一个 rightSideMenuleftSideMenu 包。每个都有自己的 ReactiveDict,我将其导出到全局范围(例如 rightMenu.RD.get('col1Hidden'))。这使方法保持模块化。我可以完全重写我的菜单代码,但只要我仍然公开 ReactiveDict,API 就保持不变。 也就是说,我仍然使用 Session 变量来显示/隐藏左右菜单。为什么?因为 Session 是菜单的完美使用。我不希望隐藏菜单在浏览器会话中持续存在(曾经关闭您不知道如何重新打开的东西?),但我确实希望它通过路线持续存在。换句话说,我希望它持续浏览会话

  • 如果你想让url保存会话信息,你需要使用params或者query params。例如,如果您有一个包含 100 个标记的地图,并且用户想要将该页面发送给他的好友并选择了一个特定的标记,那么 URL 类似于 url.com/marker20 是有意义的。但为什么要停在那里?您还可以包括地图中心的纬度和经度:url.com/marker/40.23432/122.2342。也许这太多了,也许不是。你决定。在您的示例中,这比将isTag 存储在会话变量中更有意义,因为它允许人们在不使用鼠标的情况下为其添加书签、使用后退按钮、共享和更改它(是的,您的用户群像我是)。

关于您当前设置的另一个注意事项是,您将标志用于互斥的东西,从而导致条件地狱。如果您有 2 个不能同时为真的变量,请停止并重新考虑设计。所以,如果我不得不使用会话变量,我会这样做:

 currentTemplate = Session.get('filter') 
 {{Template.dynamic template=currentTemplate}}

最后,您需要考虑的不仅仅是 ReactiveVariables。依赖关系呢?并非每个模块都需要访问每个其他模块的依赖项。集合、方法甚至 CSS 也是如此。我说让它有机地增长,当它碰到你时“嘿,这是一个组件”,然后把它变成一个包,导出一个变量,并保持模块化。在那之前,会话变量很好。

【讨论】:

    【解决方案3】:

    您的问题不是污染全局范围。那为什么不自己做呢?

    myComponentScope = {}; //Declare a global scope for this component
    

    然后在里面放多少你想要的东西。例如,

    myComponentScope.foo = new Reactive-Var('foo');
    

    如果您想要类似Session 的内容,可以添加Reactive-Dict

    meteor add reactive-dict
    

    并以这种方式使用它:

    myComponentScope = new Reactive-Dict(/* Optional name */);
    

    可选名称使字典在热代码推送中保持不变。
    该词典的 API 与Session 相同。


    因此,如果您有严格本地化的内容(一个模板),请选择 Reactive-Var
    如果是多个相同类型的模板共享的内容,请选择您自己的范围。
    如果它对您的所有应用程序都非常重要,请使用Session

    【讨论】:

    • 自定义全局范围和会话之间的根本区别是什么?您基本上可以在会话变量中使用命名空间约定,例如在他的示例中:“Main/showTags”、“Main/showQuestions”......所以只要您遵循定义的命名空间,它就不会真正污染它?
    • 是的,BraveKenny 提出了我想问的确切问题。
    • @BraveKenny 能够创建一个新的全局命名空间,而不是在 Session 中设置 someData,并在对一个非常不一致的行为进行了五个小时的调试后发现,您的一位同事也使用了someData 完全不同。 “命名空间约定”是强加给每个人的痛苦,也是容易避免的错误来源。与其将所有内容存储在同一个地方,不如将其存储在多个地方。
    • @MaximusS 是的,它会的。在这一点上,它与Session 没有什么不同。您甚至可以将其视为“另一个类似Session 的变量”。我不知道你想继承它而不是模板的孩子?如果是这样,请将其添加为模板变量并使用Template.parentData(n) 访问它。请注意,您还可以使用包方法来限制变量的范围。
    • 无法通过 parentData 访问反应变量
    猜你喜欢
    • 2015-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-09
    相关资源
    最近更新 更多