In iron router, how to avoid recompute the entire data field when only a subset is changed

StackOverflow https://stackoverflow.com/questions/23308201

  •  09-07-2023
  •  | 
  •  

Вопрос

In Iron-router, we can pass the data to a page in the data field. For example:

Router.map(function () {
  this.route('myroute', {
    path: '/route',
    template: 'myTemplate',

    data: function () {
      return {
        title: getTitle(),
        description: getDescription(), 
      }
    }
  });
});

In the template, title and description are actually some value passed to subtemplates:

<template name="myTemplate">
  {{> titleTemplate title}}
  {{> descriptionTemplate description}}
</template>

Since the data field in the iron-router is reactive, whenever a session variable change, the data field is recalculated.

In this case, however, the session variable in getTitle function only changes the template "titleTemplate", and the session variable in getDescription() function only changes the template "descriptionTemplate".

If the session variable in the getTitle() function changes, I would like to only execute the getTitle() function, and do not execute the getDescription() function. If possible, I would also like to only render the "titleTemplate" and do not render "descriptionTemplate".

I wonder whether that is possible. If this is not the right way of writing the Meteor application, what is a better way to do it?

Thanks.

Это было полезно?

Решение

This is an interesting situation. Despite the fact that the getTitle and getDescription functions may be dependent on completely different reactive variables, they will both be recomputed whenever either one of them changes.

One possible solution is to pass the functions themselves instead of the result of calling the functions. That may or may not be convenient depending on how they are used in the sub-templates, but it will prevent them from both being run every time. Here is a simple example:

<template name="myTemplate">
  {{> titleTemplate title}}
  {{> descriptionTemplate description}}
</template>

<template name="titleTemplate">
  <p>{{excitedTitle}}</p>
</template>

<template name="descriptionTemplate">
  <p>{{this}}</p>
</template>
var getTitle = function() {
  console.log('computed title');
  return Session.get('title');
};

var getDescription = function() {
  console.log('computed description');
  return Session.get('description');
};

Router.map(function() {
  this.route('home', {
    path: '/',
    template: 'myTemplate',
    data: function() {
      return {
        title: getTitle,
        description: getDescription
      };
    }
  });
});

Meteor.startup(function() {
  Session.setDefault('title', 'title1');
  Session.setDefault('description', 'description1');
});

Template.titleTemplate.excitedTitle = function() {
  return "" + (this.toUpperCase()) + "!";
};

From the console you can change the session variables (title and description) and you will see that only one function will be run at a time. I hope that helps.

Другие советы

One way to solve this is to not use the data context, but just use template specific helpers. Since I don't know what your getTitle and getDescription function do, I can't tell whether that is an option for you. It depends on whether you need to use the this object in those functions and need this to refer to the route object or not. If not, then the following seems like the better solution:

JS:

Router.map(function () {
  this.route('myroute', {
    path: '/route',
    template: 'myTemplate'
  });
});

Template.myTemplate.title = getTitle;
Template.myTemplate.description = getDescription;

HTML:

<template name="myTemplate">
  {{> titleTemplate title}}
  {{> descriptionTemplate description}}
</template>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top