Подтвердить что ты не робот

Должен ли магистральный маршрутизатор или обработчик представления данных извлекать данные и отображать статус загрузки?

Во многих местах моего приложения происходит следующее:

  • Пользователь нажимает на какую-то ссылку, запускающую навигацию.
  • Данные должны быть отображены для визуализации представления
  • Для создания пользовательского интерфейса требуется показ данных, которые будут отображаться во время загрузки данных
  • После того, как данные будут получены, мы покажем рендерное представление

Я попробовал оба следующих шаблона реализации:

  • Маршрутизатор обрабатывает выборку

    • Маршрутизатор сообщает контейнеру, чтобы показать загрузчик
    • Маршрутизатор загружает все коллекции/модели
    • Маршрутизатор сообщает контейнеру, что он скрывает загрузчик
    • Маршрутизатор передает коллекции/модели в представление и делает его
  • Просмотр образов обработок

    • Маршрутизатор просто создает и отображает представление
    • Вид выбирает коллекции и модели, в которых он нуждается.
    • Когда представление сначала отображается, оно просто показывает загрузчик загрузки, поскольку данные все еще загружаются.
    • Когда данные поступают, события пожара моделей/коллекций и представления привязаны к тем, чтобы они повторно отображались, тем самым скрывая загрузчик и отображая полный вид

Мне не нравится # 1, поскольку маршрутизатор становится гигантским шаром логики выборки Model/Collection и, похоже, несет слишком большую ответственность. # 2 кажется лучшим распределением обязанностей (маршрутизатор просто решает, какое представление показывать, просматривать, какие данные ему нужно извлечь), но это делает представление рендеринга немного более сложным, так как оно теперь имеет смысл.

Что думает сообщество StackOverflow? 1, 2 или что-то еще?

4b9b3361

Ответ 1

Этот пост довольно старый, но мы рассматривали его ранее сегодня, поэтому в случае, если кто-то еще встретит его:

Для меня я действительно вижу два отдельных вопроса:

  • Где должна возникать механика сбора данных и результирующего представления представления в маршрутизаторе или в представлении?
  • Если представления ожидают уже разрешенные модели или они должны реагировать на модели, которые все еще могут быть загружены?

Немного о том, как мы обрабатываем его в сочетании с некоторыми личными предпочтениями:

  • Ничего, хотя я бы приблизился к маршрутизатору. Маршрутизаторы должны обрабатывать маршрутизацию, представления должны обрабатывать просмотр, а что-то еще должно обрабатывать механику и рабочий процесс логики выборки Model/Collection. Мы называем это еще чем-то контроллером, которым в основном делегирует Router.
  • Как указывает Юрий, "иногда" - это реальность. Я думаю, что это, вероятно, случайное решение, но в конечном итоге должно быть контрактом между контроллером и представлением, а не между Router/View.

Мне нравятся точки выстрела Юрия, с парами предостережений (с отступом):

  • Маршрутизатор только знает, куда отправить пользователя
  • Внешний вид знает только то, что пользователь должен просматривать (учитывая его данные)
    • Предполагая, что внешний вид специфичен для внутреннего использования и является "принадлежащим" другим видом (для очистки)
    • В противном случае для универсальных контейнеров (например, рендеринга в "основное" местоположение) нам было полезно иметь компонент, который управляет представлениями для определенного "раздела" на странице - мы называем это Renderer
  • Внутренние представления только знают, как показать только их маленький кусочек всего этого (и может использоваться в другом месте)
  • и функция рендеринга всегда показывает правильную вещь прямо сейчас.
    • В случае универсального контейнера в конечном итоге это будет зависеть от Renderer

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

Пример psuedo-code-ish того, что может выглядеть, для:

  • общий целевой контент цели (если он использует конкретный случай, может быть лучше с ComponentView в соответствии с примером Yuri, в зависимости от стратегии управления жизненным циклом просмотра)
  • модель, которую мы должны получить и ждать
  • представление, которое принимает уже загруженную модель

Маршрутизатор:

routes: {
    "profile": "showProfile"
},

showProfile: function() {
    return new ProfileController().showProfile();
}

ProfileController:

showProfile: function() {
    //simple case
    var model = new Model();
    var deferredView = model.fetch.then(function() {
        return new View(model);
    };
    MainContentRenderer.renderDeferred(deferredView);
}

MainContentRenderer:

var currentView;

renderDeferred: function(deferredView) {
    showSpinner();
    deferredView.then(function(view) {
        this.closeSpinner();
        this.closeCurrentView();
        this.render(view);
    }
},

render: function(view) {
    currentView = view;
    $('#main-content').html(view.render().el);
}

closeCurrentView: function() {
    if (currentView and currentView.close()) {
        currentView.close();
    }
}

Представление контроллера также имеет дополнительное преимущество проверки. Например, у нас есть сложные правила для выполнения поиска по управлению URL-адресами, выбора между представлением результатов и новым поисковым представлением и выбора между кэшированным "последним" результатом поиска и выполнением нового поиска. У нас есть тесты Jasmine для контроллеров, чтобы проверить правильность всей этой логики потока. Он также обеспечивает изолированное место для управления этими правилами.

Ответ 2

Я предпочитаю использовать второй вариант с тремя представлениями, контейнером, представлением загрузки и представлением содержимого. То есть, контейнер создается экземпляром маршрутизатора, и во время каждого рендеринга он смотрит на то, что он может отображать, иногда предоставляемый маршрутизатором, иногда сам по себе, и решает, какие объекты должны создаваться. Простой, надуманный пример:

ContainerView = Backbone.View.extend({

  initialize: function (options) {
    options.data.bind("reset", this.render, this);
  },

  render: function () {
    var view;

    // If the loading view is only shown once, e.g., splashing, then isReady()
    // may be better here.
    if (this.options.data.isLoading()) {
      view = LoadingView;
    } else {
      view = DataView;
    }

    this.$("div.content").html(new view().render().el);
  }

});

Мне нравится этот подход, потому что:

  • Маршрутизатор только знает, куда отправить пользователя;
  • Внешний вид знает только то, что пользователь должен просматривать (учитывая его данные);
  • Внутренние представления только знают, как показывать только их маленький кусочек всего (и можно использовать в другом месте); и
  • Функция рендеринга всегда показывает правильную вещь прямо сейчас.

Разъяснение: Целью представления в данном случае является понимание того, что должно показать, что лучше показать пользователю. В этом случае бит загрузки данных лучше всего отображать с представлением загрузки, тогда как готовые данные лучше всего показывать с представлением данных. Большинство реальных представлений на самом деле составляют их отображение со многими другими видами, например, в зависимости от пользовательских разрешений различных контейнеров действий.