Привязать шаблон к массиву ReactiveVar в Метеоре - PullRequest
0 голосов
/ 09 октября 2018

У меня есть следующий сценарий:

У меня есть следующий шаблон:

<ul>
  {{#each persons}}
     {{Name}}
  {{/each}}
</ul>

где persons = ReactiveVar([]) в файле шаблона .js.и я обновляю переменную лиц в обратном вызове HTTP Rest API:

var instance = Template.instance();
API(url, (error, result) = instance.persons.set(result)) //result is an array

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

1 Ответ

0 голосов
/ 09 октября 2018

Привязка внешних API к шаблону может быть решена с помощью классического экземпляра шаблона 'ReactiveVar / ReactiveDict (назовем их реактивным источником).Обратите внимание, что вы не должны делать эти вызовы или обновления для реактивного источника в помощнике, а внутри события или внутри onCreated.

Давайте возьмем ваш шаблон:

<ul>
  {{#each persons}}
     {{Name}}
  {{/each}}
</ul>

Затем мы сделаемвызов внутри функции onCreated:

Template.myTemplate.onCreated(function () {
  const instance = this
  instance.state = new ReactiveDict()
  instance.state.set('persons', [])

  // Template's internal tracker
  instance.autorun(() => {

    API(url, (error, result) => instance.state.set('persons', result)) //result is an array
  })
})

и возврат данных только по реактивному источнику в помощнике:

Template.myTemplate.helpers({
  persons() {
    return Template.instance().state.get('persons')
  }
})

Теперь возникает другая проблема: внешний API обычно нереактивный, вызывая триггер от autorun до , а не снова, если данные во внешнем API изменились.Если источником будет коллекция Mongo, внутренний Tracker шаблона автоматически перезапустится и обновит ваше состояние persons.

Если вы хотите получить внешние данные только один раз, это нормально.Однако, чтобы scan внешний API для изменений, у вас есть несколько различных опций:

Простой способ: использовать таймер (setInterval):

let timerId

Template.myTemplate.onCreated(function () {
  const instance = this
  instance.state = new ReactiveDict()
  instance.state.set('persons', [])

  timerId = setInterval(() => {
    API(url, (error, result) => instance.state.set('persons', result)) //result is an array
  }, 5000) // scans each 5 seconds for updates
})

Template.myTemplate.onDestroyed(function () {
  if (timerId) {
    clearInterval(timerId)
    timerId = null
  }
})

Плюсы

  • Простота реализации
  • Мелкозернистая настройка времени для беглого опыта

Минусы

  • setInterval - это раковина
  • вы должны очистить его, чтобы предотвратить утечки памяти (в onDestroyed)

Трудный путь: позвольте службе внешнего API звонить вам!

Если у вас есть возможность разрешить подключаться внешней службе и вызывать ваше приложение через ddp , вы можете разрешить внешней служберешить, когда данные изменились и готовы к запуску, чтобы ваше текущее приложение могло обновляться автоматически.

Для этого вам нужен метод и коллекция:

сервер и клиент:

export const ExternalData = new Mongo.Collection('externalData')

сервер:

import ExternalData from 'path/to/externalData'

Meteor.methods({
  'myApp.updateExternalData'(args) {
     // check permissions...
     // check data integrity...
     const {url} = args
     const {data} = args
     ExternalData.update({url}, {$set: data})
   }
})

Meteor.publish({
 'myApp.externalData'(url) {
   return ExternalData.find({url})
 }
})

Теперь на клиенте вам просто нужно подписаться на данныеи обновите реактивную переменную автоматически:

клиент:

import ExternalData from 'path/to/externalData'

Template.myTemplate.onCreated(function () {
  const instance = this

  // subscribe to changes
  instance.autorun(() => {

    const subscription = this.subscribe('myApp.externalData', url)
    if (subscription.ready()) {
       console.log('myApp.externalData is ready')
    }
  })
})

Template.myTemplate.helpers({
  persons() {
    return ExternalData.find({})
  }
})

Внешняя служба / приложение:

// if the external app is a meteor app you are lucky and can go with:
// https://docs.meteor.com/api/connections.html#DDP-connect
// Otherwise you can use the npm package:
// https://www.npmjs.com/package/ddp
// For authentication you can use:
// https://github.com/reactioncommerce/meteor-ddp-login
// or
// https://www.npmjs.com/package/ddp-login
const connection = // create a ddp connection

function onDataChanged () {
  const data = //... get data from the backend of your ext. servie
  const url  = //... and the url for which the data is relevant

  // call the app to update the data:
  connection.call('myApp.updateExternalData', {url, data})
}

Плюсы:

  • Шаблон автоматически обновляется при обновлении коллекции
  • Нет таймеров = нет приемников!
  • Не требуется никаких дополнительных реактивных переменных
  • Вы можете использоватьколлекция, чтобы сделать внешние данные постоянными, кэшировать их или создать ревизию / историю
  • Вы можете подключать / отключать внешние службы (лучшее масштабирование, меньше зависимостей)

Минусы:

  • Высокая кривая обучения (но это стоит усилий)
  • Работает, только если у вас есть контроль над внешней службой
  • Больше кода = больше потенциальных ошибок, поэтому больше тестов для записи
...