什么时候应该使用Session
和ReactiveVar
?我使用Session
变量作为组件之间的通信媒介。我们来看看Stackoverflow。
我标记了三个假设成分。我们来看看filters
组件。如果您点击Tags
,则Main
组件会根据您最喜欢的标签显示其问题。为此,我会在点击Session.set("Main/showTags", true)
按钮时设置Tags
。在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
进行操作其他
这是我的最后一个问题。如何正确使用Session
和ReactiveVar
来保持组件的范围并使它们彼此通信?另外,如果我按现在的方式使用Session
,我是否会不必要地污染全局命名空间?
相关文件:
答案 0 :(得分:11)
据我所知,没有与Session
变量相关的内置功能可以将它们与您要声明的常规反应词典全局变量(如@Kyll所述)区分开来,例如,在您的client.js
文件中。唯一的区别是Session
“限制”是必要的可访问应用程序范围。
当我在较小的范围内使用reactive dictionary或reactive variables时,我很高兴能利用这种差异。我认为我有三种范围:
1 - 全球范围 。例如。当前的UI语言,UI皮肤。我使用Session
。简单的全局数据,而不是那种可能与其他任何东西混淆的数据。
2 - 一组模板。 比方说,我创建了一个页面,用于在我的应用中生成和自定义pdf。我不会在其他地方重用任何组件。我的群集是一个包含三个文件的文件夹,我们称之为pdfgenerator.html
,pdfgenerator.js
和pdfgenerator_controller.js
。
我使用pdfgenerator_controller.js
来扩展具有所有细节的路线。
在pdfgenerator.js
文件中,我有几个模板,我都在群集中使用。在文件的开头,我创建了一个反应式字典pageSession
(类似于反应变量),我在我的所有集群中使用它。它允许我在所有组件之间传递数据。
3 - 本地范围。 无论是单个模板还是可重复使用的组件,它都可以单独使用。我也不会将Session vars用于那些。我不想过度拥护Session
名称空间。我所做的是将我在实例化过程中运行它所需的每个数据传递给我的模板。
可能来自Spacebars:
{{> mySingleTemplate data=myData}}
或使用Javascript:
Blaze.renderWithData(Template.mySingleTemplate , myData, self.firstNode);
在本地范围的情况下,我还使用reactive dictionary
或reactive vars
来处理单个模板中发生的反应。在这种情况下,我尝试避免需要将数据反应性地返回到父模板的情况。如果我必须(即我不可能从中创建一个包),我使用在父模板范围内声明为全局的本地 minimongo 集合。这样,我可以将可重用组件的信息传递给它的父组件。
示例:上传模板。我使用minimongo来存储每个上传文件的名称,大小,类型,状态和URL。 minimongo集合在父表单模板和子上传器模板之间共享。
底线: 我只使用Session
变量来获取基本信息和全局信息。如果我需要全局共享的数据结构太复杂/太大,我依赖于一个集合。
我很想知道我是否做对了,所以这是一个答案,而不是一个测试,看看人们是否同意我的做事方式。欢迎提出所有意见和建议。
答案 1 :(得分:5)
会话变量得到了糟糕的说唱。事实是,在你的应用变大之前,它们会很好。您知道在以下情况下何时离开Session vars:
isColumnHidden
再次意味着什么?)或者,会话变量形成自然集群(工具提示3个会话变量,标签5个变量等)。 那么,你如何解决每个问题?
对于第一个示例,请创建一个包。例如,在我的一个较大项目中,我创建了一个rightSideMenu
和leftSideMenu
包。每个都有自己的ReactiveDict,我将其导出到全局范围(例如rightMenu.RD.get('col1Hidden')
)。这使方法模块化。我可以完全重写我的菜单代码,但只要我仍然公开ReactiveDict,API保持不变。 那说,我仍然使用Session var来显示/隐藏左边&正确的菜单。为什么?因为Session是菜单的完美用途。我不希望隐藏的菜单通过浏览器会话持续存在(关闭你不知道如何重新打开的东西?),但我确实希望它能够通过路由持续存在。换句话说,我希望它能够持续浏览 Session 。
如果您希望网址保存会话信息,则需要使用参数或查询参数。例如,如果您有一张包含100个标记的地图,那么用户想要通过选择特定标记将该页面发送给他的好友,这样的网址就像url.com/marker20
一样。但为何停在那里?您还可以包括lat& lng地图中心:url.com/marker/40.23432/122.2342
。也许那太多了,也许不是。你决定。在您的示例中,这比在会话var中存储isTag
更有意义,因为它允许人们将其加入书签,使用后退按钮,共享它,并在不使用鼠标的情况下更改它(是的,您的用户库是像我一样懒。)
关于当前设置的另一个注意事项是,您正在使用标记来处理互斥的内容,从而导致条件地狱。如果您有2个不能同时为真的变量,那么停止&重新思考设计。所以,如果我不想使用会话变量,我会做类似的事情:
currentTemplate = Session.get('filter')
{{Template.dynamic template=currentTemplate}}
最后,您需要考虑的不仅仅是ReactiveVariables。依赖关系怎么样?并非每个模块都需要访问每个其他模块的依赖关系。集合,方法甚至CSS也是如此。我说让它有机地生长和放大当它击中你时,嘿,这是一个组件"然后将其转换为包,导出变量,并保持模块化。在那之前,Session vars很好。
答案 2 :(得分: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
。