由于 Meteor 升级到 0.8.0,当 Session 变量依赖发生变化时,不会触发模板“rendered”回调

Posted

技术标签:

【中文标题】由于 Meteor 升级到 0.8.0,当 Session 变量依赖发生变化时,不会触发模板“rendered”回调【英文标题】:Since Meteor upgrade to 0.8.0, Template "rendered" callback is not fired when Session variable dependancy changes 【发布时间】:2014-05-09 09:37:59 【问题描述】:

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

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

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

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

这完美地说明了这个问题,因为在这个例子中,rendered 只触发了两次:

client/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);

client/each.html

<body>
  > list
</body>

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

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

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

谢谢,

【问题讨论】:

我确实有同样的问题,这看起来可能是设计更改。还没找到解决办法。 【参考方案1】:

所以,我昨天做了很多挖掘工作,试图找出与您遇到的基本完全相同的问题。我还在挖掘,但我确实遇到了这个 Devshop Talk about Integrating Other Clientside JS Libraries。在其中 Ted Blackman 描述了他制作的一个包,用于在 Session 变量更改时触发事件。这听起来像你需要的。这个演讲是在 0.8.0 之前进行的,所以我不确定这个包会如何影响,但它可能值得一试。

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

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

事件视界 - https://atmospherejs.com/package/event-horizon

【讨论】:

【参考方案2】:

正如 cmets 中所述,这确实是 Meteor 的设计更改。

在 Meteor 0.8 之前,模板是一个生成 html 的函数。每当它的任何反应性依赖项发生变化时,都会重新计算该函数,从而重新创建由模板生成的所有 DOM 节点(除了任何子模板或孤立节点)。每当重绘发生时,都会触发rendered 回调。

这种行为会造成相当大的性能损失,因为它需要重新渲染可能大量的 HTML,包括标识符和帮助器,具体取决于未更改的数据。此外,使用 jQuery 等其他库来修改创建的 DOM 元素也很困难,因为 Meteor 基本上可以控制整个过程,并且每次都必须小心地重新运行 jQuery 代码。

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

有关 Spacebars(新的 Handlebars 替代品)工作原理的更详细列表,请参阅 https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md

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

【讨论】:

【参考方案3】:

我确实为您提供了一个即时解决方案,但它可能需要稍微重新考虑您的实际代码。顺便说一句,这和这里的问题是一样的:

Meteor 0.8.0 - Failed to operate DOM in rendered callback

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

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

Blaze 以非常不同的方式处理“如何对更改的依赖项做出反应”这一整件事,“更好”的人可能会说:它会识别 DOM 节点所在的“一”、“二”或“三”(在您的如果它是模板本身)被存储并只替换已更改的部分,即文本内容“一”、“二”或“三”。 DOM 节点本身以及模板保持完整。这也意味着,在几乎所有实际场景中,您可以使用此 DOM 节点执行的所有操作都不必重新执行。 IE。如果你为它设置动画,使用 jQuery 改变它的文本颜色,颜色和动画只会留在屏幕上,所以你不需要渲染的回调来重新做。

在您的情况下,只需重新安排您想要在“重新渲染”上执行的操作即可轻松解决问题:

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()

在您的特定示例中,您的“logRender”函数没有任何反应性依赖项,但如果您添加一些并将其放入Deps.autorun(),只要依赖项发生变化,它就会可靠地重新运行。

总而言之,Meteor 0.7.x 及以下版本让我们犯了将“渲染”回调函数视为通用自动运行函数的错误,这就是为什么我们现在遇到麻烦并且必须修复我们的应用程序的原因。

【讨论】:

他的回答很完整,我学到了一些东西。然而,这并没有解决我的问题,因为模板没有像在 Session.set() 触发 html(重新)生成之后那样创建 DOM,可能是因为许多级联模板。我不得不重写很多东西,并且不再依赖模板响应式计算来创建我需要的 DIV。简而言之,在我的 节点被渲染/创建之后,我没有找到一种方法来与调用我的 javascript 部分的“渲染”行为竞争。 很抱歉,根据您的应用程序的结构,重写一些(或更多)代码可能是不可避免的。 docs.meteor.com 中关于模板实例的更新部分,UI.insert()UI.render() 以及 jQuery 的正确使用(通过 jQuery 传递所有 DOM 操作)对我处理 0.8.0 更新有很大帮助。跨度>

以上是关于由于 Meteor 升级到 0.8.0,当 Session 变量依赖发生变化时,不会触发模板“rendered”回调的主要内容,如果未能解决你的问题,请参考以下文章

Meteor 0.8.0:构建应用程序时:意外的关闭模板标签

MIME 消息无效 AWS SES 由于 MIME 消息无效而拒绝它

NACOS升级操作

Meteor 开发人员 - 有没有人修复 Meteor 无法在 iOS 10 iPhone 6 Plus 上运行的问题?

boto3 ses InvalidParameterValue 错误由于 unicode 字符

在 Meteor 1.3 + angular1 上使用 npm(凹凸!)