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
- デストラクタを実装する
コントローラー
- 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 は分離しておいたほうがよい。