Facebook любит загружать новые сообщения в метеоре

Я в процессе изучения метеора. Я следовал руководству по созданию микроскопа. Если кто-то отправит сообщение, метеор повторно отобразит шаблон для всех пользователей. Это может быть очень раздражающим, если есть сотни сообщений, тогда пользователь вернется к началу страницы и потеряет информацию о том, где он был. Я хочу реализовать что-то похожее на то, что есть в facebook. Когда новый пост отправлен, шаблон не отображается, а появляется кнопка или ссылка. Нажатие на нее приведет к повторному рендерингу шаблона и отображению новых сообщений.

Я думал об использовании observeChanges в коллекции для обнаружения любых изменений, и это не позволяет странице показывать новые сообщения, но единственный способ показать их - перезагрузить страницу.

Meteor.publish('posts', function(options) {
  var self = this, postHandle = null;

  var initializing = true;

  postHandle = Posts.find({}, options).observeChanges({
    added: function(id, post) {

      if (initializing){
          self.added('posts', id, post);
      } 
    },
    changed: function(id, fields) {
      self.changed('posts', id, fields);
    }
  });

  self.ready();
  initializing = false;
  self.onStop(function() { postHandle.stop(); });
});

Это правильный путь? Если да, то как мне предупредить пользователя о новых сообщениях? Иначе, что было бы лучшим способом реализовать это?

Спасибо


person Guranjan Singh    schedule 10.07.2015    source источник


Ответы (2)


Это сложный вопрос, но также ценный, поскольку он относится к шаблону проектирования, применимому во многих случаях. Одним из ключевых аспектов является желание знать, что есть новые данные, но не желание показывать их (пока) пользователю. Мы также можем предположить, что когда пользователь действительно хочет видеть данные, он, вероятно, не хочет ждать, пока они будут загружены в клиент (так же, как Facebook). Это означает, что клиенту по-прежнему необходимо кэшировать данные по мере их поступления, а не отображать их сразу.

Поэтому вы, вероятно, не хотите ограничивать данные, отображаемые в публикации, потому что это не приведет к отправке данных клиенту. Скорее, вы хотите отправить все (соответствующие) данные клиенту и кэшировать их там, пока они не будут готовы.

Самый простой способ — иметь временную метку в ваших данных для работы. Затем вы можете соединить это с реактивной переменной, чтобы добавлять новые документы в отображаемый набор только при изменении этой реактивной переменной. Что-то вроде этого (код, вероятно, будет в разных файлах):

// Within the template where you want to show your data
Template.myTemplate.onCreated(function() {
  var self = this;
  var options = null; // Define non-time options

  // Subscribe to the data so everything is loaded into the client
  // Include relevant options to limit data but exclude timestamps
  self.subscribe("posts", options);

  // Create and initialise a reactive variable with the current date
  self.loadedTime = new ReactiveVar(new Date());

  // Create a reactive variable to see when new data is available
  // Create an autorun for whenever the subscription changes ready() state
  // Ignore the first run as ready() should be false
  // Subsequent false values indicate new data is arriving
  self.newData = new ReactiveVar(false);
  self.autorun(function(computation) {
    if(!computation.firstRun) {
      if(!self.subscriptionsReady()) {
        self.newData.set(true);
      }
    }
  });
});

// Fetch the relevant data from that subscribed (cached) within the client
// Assume this will be within the template helper
// Use the value (get()) of the Reactive Variable
Template.myTemplate.helpers({
  displayedPosts = function() {
    return Posts.find({timestamp: {$lt: Template.instance().loadedTime.get()}});
  },

  // Second helper to determine whether or not new data is available
  // Can be used in the template to notify the user
  newData = function() {
    return Template.instance().newData.get();
});

// Update the Reactive Variable to the current time
// Assume this takes place within the template helper
// Assume you have button (or similar) with a "reload" class
Template.myTemplate.events({
  'click .reLoad' = function(event, template) {
    template.loadedTime.set(new Date());
  }
});

Я думаю, что это самый простой шаблон, чтобы охватить все вопросы, которые вы поднимаете. Это становится более сложным, если у вас нет метки времени, у вас есть несколько подписок (тогда вам нужно использовать дескрипторы подписки) и т. д. Надеюсь, это поможет!

person Duncan Foster    schedule 10.07.2015
comment
Это не работает. Он останавливает повторный рендеринг, но для newData никогда не устанавливается значение true. - person Guranjan Singh; 17.07.2015
comment
Извиняюсь. Похоже, что subscriptionsReady() может быть нереактивным (документы не ясны), но дополнительный помощник шаблона. Поэтому автозапуск не сработает. Вместо этого вам может понадобиться использовать метод ready() в дескрипторе подписки или обратный вызов onReady() в функции подписки. - person Duncan Foster; 20.07.2015

Как сказал Дункан в своем ответе, ReactiveVar - это путь. На самом деле я реализовал простую страницу ленты Facebook с метеором, где я отображаю общедоступные сообщения с определенной страницы. Я использую бесконечную прокрутку, чтобы добавлять сообщения внизу страницы и сохранять их в ReactiveVar. Проверьте исходники на github здесь и живую демонстрацию здесь. Надеюсь, поможет!

person Cristian    schedule 10.07.2015