Backbone.js : View を使いまわす

View を使いまわしたくて、次のようなコードを書いたとする:

var ActionsView = Backbone.View.extend({
  events: {
    'click .show': 'showContent',
    'click .change': 'changeContent',
  },
  showContent: function(event) {
    // じゃんじゃかインスタンスを生成
    $('#content').html(new ContentView({model: this.model}).render().el);
  },
...
});

クリックされるたびに ContentView を生成する。

具体的に、次のようなケースにおいて、実害がある:

var ActionsView = Backbone.View.extend({
...
  changeContent: function(event) {
    // モデルに値を設定する
    this.model.set({timeStamp: event.timeStamp});
  },
...
});

var ContentView = Backbone.View.extend({
  initialize: function() {
    // モデルを監視する
    this.model.on('change', this.onChange, this);
  },
  onChange: function() {
    // インスタンス数のぶんだけコールされる
    console.log(this.model.get('timeStamp'));
  },
});

解決

  • View

    • デストラクタを実装する
  • コントローラー

var ActionsView = Backbone.View.extend({
...
    showContent: function(event) {
      // $('#content').html(new ContentView({model: this.model}).render().el);
      ViewController.show($('#content'), new ContentView({model: this.model}));
    },
...
});

var ContentView = Backbone.View.extend({
...
    close: function(){
      this.remove();
      this.unbind();
      // unbind は on と同じパラメータを渡すこと
      this.model.unbind("change", this.onChange, this);
    },
});

var ViewController = ViewController || {
  close: function(selector) {
    if (this.currentView) {
      this.currentView.close();
    }
    selector.empty();
  },
  show: function(selector, view) {
    this.close(selector);
    this.currentView = view;
    this.currentView.render();
    selector.html(this.currentView.el);
    return this.currentView;
  },
}

使いまわすということは、単純に消したいケースもあるはずなので、 close は分離しておいたほうがよい。

参考記事