autorun 的反应式计算可以依赖于集合的一部分吗?
Can autorun's reactive computation be dependent on part of a collection?
我想在 Meteor 中创建一个具有 Tracker.autorun 的模板,当文档的一部分发生变化时,它专门 运行s --- 但当文档的其他部分发生变化时则不会。
所以这是使用 minimongo 集合和 template.autorun
的示例代码
parent.html
{{#each items}}
{{> child}}
{{/each}}
child.html
<div>{{title}}</div>
<p>{{description}}</p>
Minimongo 合集
LocalProject.findOne() output:
"items": [
{
"title": "hi",
"description": "test"
},
{
"title": "hi 2",
"description": "test 2"
},
],
"otherstuff:{//etc}
child.js
Template.child.onRendered(function(){
this.autorun(function() {
var data = Template.currentData();
doSomething(data.title,data.description)
});
});
addnewitem.js
LocalProject.update(currentEditingProjectID,{ $push: { 'items': newItem }},function(error,result){
if(error){console.log(error)}
});
问题是,每当我 运行 addnewitem.js 时,我所有的 Template.child auto运行 都会执行,即使它们的反应数据源(Template.currentData ()) 没有改变,除非它是我更新的特定项目。同样,如果我想更新现有项目,而不仅仅是向数组添加新项目,则会执行每个项目的所有 auto运行s。
那么有没有一种方法可以使用此模型为 auto运行 创建对文档的特定部分具有反应性粒度的依赖项?
有一个专门用于此的工具 - 3stack:embox-value 提供反应隔离和值缓存。
使用您的示例,您可以隔离对 title/description 的更改,如下所示:
首先,添加包
meteor add 3stack:embox-value
meteor add ejson
然后,更新您的代码:
Template.child.onRendered(function(){
// creates a reactive data source, that only triggers "changes"
// when the output of the function changes.
var isolatedData = this.emboxValue(function(){
var data = Template.currentData();
return {title: data.title, description: data.description}
}, {equals: EJSON.equals})
this.autorun(function() {
// This autorun will only execute when title or description changes.
var data = isolatedData()
doSomething(data.title,data.description)
});
});
我不认为使用自动运行是可行的方法。我会为每个项目设置单独的反应依赖项,或者使用 observe
/observeChange
.
第一个想法
parent.html:
{{#each items}}
{{> child}}
{{/each}}
parent.js:
Template.parent.helpers({
// Returns only item ids
items: function() {
return Items.find({}, { fields: { _id: 1 } });
}
});
child.html:
{{#each items}}
{{#with item=getItem}}
<div>{{item.title}}</div>
<p>{{item.description}}</p>
{{/with}}
{{/each}}
child.js:
Template.child.helpers({
getItem: function() {
// Get the item and set up a reactive dependency on this particular item
var item = Items.find(this._id);
// After item has been displayed, do something with the dom
Tracker.afterFlush(function () {
doSomething(item.title, item.description);
});
return item;
}
});
第二个想法
parent.html:
{{#each items}}
{{> child}}
{{/each}}
parent.js:
function do(item) {
Tracker.afterFlush(function () {
doSomething(item.title, item.description);
});
}
Template.parent.onCreated({
this.items = Items.find({});
this.handle = this.items.observe({
added: function(item) { do(item); },
changed: function(oldItem, newItem) { do(newItem); },
});
});
Template.parent.onDestroyed({
this.handle.stop();
});
Template.parent.helpers({
items: function() {
return Template.instance().items;
}
});
child.html:
{{#each items}}
<div>{{title}}</div>
<p>{{description}}</p>
{{/each}}
我想在 Meteor 中创建一个具有 Tracker.autorun 的模板,当文档的一部分发生变化时,它专门 运行s --- 但当文档的其他部分发生变化时则不会。 所以这是使用 minimongo 集合和 template.autorun
的示例代码parent.html
{{#each items}}
{{> child}}
{{/each}}
child.html
<div>{{title}}</div>
<p>{{description}}</p>
Minimongo 合集
LocalProject.findOne() output:
"items": [
{
"title": "hi",
"description": "test"
},
{
"title": "hi 2",
"description": "test 2"
},
],
"otherstuff:{//etc}
child.js
Template.child.onRendered(function(){
this.autorun(function() {
var data = Template.currentData();
doSomething(data.title,data.description)
});
});
addnewitem.js
LocalProject.update(currentEditingProjectID,{ $push: { 'items': newItem }},function(error,result){
if(error){console.log(error)}
});
问题是,每当我 运行 addnewitem.js 时,我所有的 Template.child auto运行 都会执行,即使它们的反应数据源(Template.currentData ()) 没有改变,除非它是我更新的特定项目。同样,如果我想更新现有项目,而不仅仅是向数组添加新项目,则会执行每个项目的所有 auto运行s。
那么有没有一种方法可以使用此模型为 auto运行 创建对文档的特定部分具有反应性粒度的依赖项?
有一个专门用于此的工具 - 3stack:embox-value 提供反应隔离和值缓存。
使用您的示例,您可以隔离对 title/description 的更改,如下所示:
首先,添加包
meteor add 3stack:embox-value
meteor add ejson
然后,更新您的代码:
Template.child.onRendered(function(){
// creates a reactive data source, that only triggers "changes"
// when the output of the function changes.
var isolatedData = this.emboxValue(function(){
var data = Template.currentData();
return {title: data.title, description: data.description}
}, {equals: EJSON.equals})
this.autorun(function() {
// This autorun will only execute when title or description changes.
var data = isolatedData()
doSomething(data.title,data.description)
});
});
我不认为使用自动运行是可行的方法。我会为每个项目设置单独的反应依赖项,或者使用 observe
/observeChange
.
第一个想法
parent.html:
{{#each items}}
{{> child}}
{{/each}}
parent.js:
Template.parent.helpers({
// Returns only item ids
items: function() {
return Items.find({}, { fields: { _id: 1 } });
}
});
child.html:
{{#each items}}
{{#with item=getItem}}
<div>{{item.title}}</div>
<p>{{item.description}}</p>
{{/with}}
{{/each}}
child.js:
Template.child.helpers({
getItem: function() {
// Get the item and set up a reactive dependency on this particular item
var item = Items.find(this._id);
// After item has been displayed, do something with the dom
Tracker.afterFlush(function () {
doSomething(item.title, item.description);
});
return item;
}
});
第二个想法
parent.html:
{{#each items}}
{{> child}}
{{/each}}
parent.js:
function do(item) {
Tracker.afterFlush(function () {
doSomething(item.title, item.description);
});
}
Template.parent.onCreated({
this.items = Items.find({});
this.handle = this.items.observe({
added: function(item) { do(item); },
changed: function(oldItem, newItem) { do(newItem); },
});
});
Template.parent.onDestroyed({
this.handle.stop();
});
Template.parent.helpers({
items: function() {
return Template.instance().items;
}
});
child.html:
{{#each items}}
<div>{{title}}</div>
<p>{{description}}</p>
{{/each}}