由于Meteor升级到0.8.0,因此当会话变量依赖性更改时,不会触发模板“呈现”回调

时间:2014-03-29 22:58:16

标签: javascript meteor spacebars

自从我升级到0.8.0后,我遇到了问题。 渲染的模板不再被触发(第一次除外)。

我遵循以下建议: https://github.com/avital/meteor-ui-new-rendered-callback/blob/master/new2/client/each.js

这没有帮助,所以我最终制作了这一小段代码(通过修改new2示例)。

主要区别在于更新是由Session变量而不是DB更改触发的。

这完美地显示了问题,因为渲染仅使用此示例触发两次:

的客户机/ each.js

Template.list.items = function () {
  return (Session.get('items') || 'None')
};

var renderCount = 1;
var logRender = function () {
  console.log("rendered #" + renderCount);
  renderCount++;
};

Template.list.rendered = function () {
  logRender();
};

Template.justName.rendered = function () {
  logRender();
};

setInterval(function () {
  Session.set('items', {name: Random.choice(["one", "two", "three"])});
}, 1000);

的客户机/ each.html

<body>
  {{> list}}
</body>

<template name="list">
   {{#with items}}
   {{> justName}}
   {{/with}}
</template>

<template name="justName">
  {{name}}
</template>

如何在Session.set触发内容更新时正确触发Template.justName.rendered回调?

谢谢,

3 个答案:

答案 0 :(得分:3)

我确实为您提供了即时解决方案,但它可能需要对您的实际代码进行一些重新思考。顺便提一下,问题就在这里:

Meteor 0.8.0 - Failed to operate DOM in rendered callback

但问题是在这样一个不同的背景下提出的,回答两次是有意义的。

那么为什么它不会触发渲染的回调呢?因为它不会重新渲染。

Blaze对待整个事情&#34;如何对变化的依赖关系作出反应&#34;非常不同,&#34;更好&#34;有人可能会说:它会识别你的&#34; one&#34;,&#34; two&#34;或&#34;三&#34; (在你的情况下,它是模板本身)存储在并且只是替换已经改变的部分,即文本内容&#34; one&#34;,&#34; two&#34;或&#34;三&#34;。 DOM节点本身以及模板完全保持不变。这也意味着,几乎在每个实际场景中,您在本DOM节点上所做的一切都不必重新完成。即如果你为它设置动画,使用jQuery更改它的文本颜色,颜色和动画将保留在屏幕上,所以你不需要渲染的回调来重新执行它。

在您的情况下,只需重新安排您想要做的事情即可轻松解决问题&#34; rerender&#34;:

var whatever = function(){
    // whatever you want to do on data-change, in your case calling "logRender" (which needs to be renamed with Blaze, anyway..)
    logRender();
}

然后你唯一需要做的就是在数据发生变化时手动启动它,如下所示:

setInterval(function () {
    Session.set('items', {name: Random.choice(["one", "two", "three"])});
    // calling the function when changing the data, knowing that it WON'T destroy the DOM node it affects
    whatever();
}, 1000);

或反应性,像这样:

Deps.autorun(function(){
    Session.get("items"); // our dependency, just has to be there, but you can also use it
    whatever(); // will be fired whenever dependency changes
});

核心思想是消除重新执行在渲染回调中所做的事情的需要,因为DOM及其对象的身份(以及所有漂亮的jQuery效果)仍然完好无损。因此,重新做的只是依赖于特定的被动数据变化,这就是Deps.autorun()的原因。

在您的特定示例中,您的&#34; logRender&#34;函数没有任何反应依赖,但如果你添加一些并将它放入Deps.autorun(),它将在依赖项发生变化时可靠地重新运行。

作为一个结论,Meteor 0.7.x及以下版本驱使我们犯了错误,即处理&#34;渲染&#34;回调函数作为通用自动运行功能,这就是为什么我们现在遇到麻烦并且必须修复我们的应用程序。

答案 1 :(得分:0)

正如评论中所指出的,这确实是Meteor的设计变更。

在Meteor 0.8之前,模板是一个生成HTML的函数。只要其任何反应依赖关系发生变化,就会重新计算此函数,从而重新创建模板生成的所有DOM节点(除了任何子模板或隔离节点)。每当重新绘制时,都会触发rendered回调。

这种行为会产生很大的性能影响,因为它需要重新呈现潜在的大量HTML,包括标识符和帮助程序,具体取决于尚未更改的数据。另外,它很难使用像jQuery这样的其他库来修改创建的DOM元素,因为Meteor基本上可以控制整个过程,每次都必须仔细重新运行jQuery代码。

Meteor 0.8通过仅渲染实际已更改的DOM片段来修复此问题,降低到模板中标识符的粒度 - 它更精细。因此,模板的rendered回调仅在您的模板点击页面时触发一次,之后再也不会再次调用。这解决了许多性能问题,并允许jQuery和其他DOM操作与Meteor无缝协作,但也意味着当某些内容发生变化时,您将无法获得自动回调信号。但是,您可以通过帮助程序实现此目的,这些帮助程序将使用反应变量来处理更改的特定事物。

有关如何使用新的把手替代品Spacebars的详细列表,请参阅https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md

另请参阅有关渲染回调的新文档:http://docs.meteor.com/#template_rendered

答案 2 :(得分:0)

所以,我昨天做了很多挖掘工作,试图找出你所遇到的完全相同的问题。我还在挖掘,但我确实遇到过关于集成其他客户端JS库的Devshop演讲。在其中,Ted Blackman描述了他在Session变量发生变化时触发事件的包。这听起来像你需要的。这次谈话是在0.8.0之前给出的,所以我不确定这个包是如何实现的,但它可能值得一试。

Devshop Talk - https://www.youtube.com/watch?v=NdBPY98o6eM

会话附加内容 - https://atmospherejs.com/package/session-extras

活动地平线 - https://atmospherejs.com/package/event-horizon