はじめに
React、Vue、Svelte……フロントエンドのフレームワークは次々と登場しますが、 「データが変わったら画面のどこを更新すべきか」「複数のコンポーネントで同じ状態を どう共有するか」といった悩みは、実はどのフレームワークでも共通しています。
Backbone.jsは、こうした悩みに2010年という早い時期から向き合ってきたライブラリです。
Model・View・Collection・Routerという最小限の部品だけを提供し、
残りの設計判断は開発者に委ねる。この潔さが、今でも一定の支持を集めている理由です。
とはいえ、読むより触った方が早いと思います。Backbone.jsのModelが値の変更を
検知してイベントを発火する様子を、実際に動くサンプルで見られます。
先に挙動を見たい方はこちらからどうぞ。
Backbone.jsとは
Backbone.jsは、Jeremy Ashkenas氏が2010年に公開したJavaScriptライブラリです。
RESTfulなAPIとの連携を前提に、Modelでデータとロジックを、Viewで描画を、
Collectionでモデルの集合を、RouterでURLとの対応をそれぞれ担当させることで、
jQueryの直接操作だけでは肥大化しがちなコードに構造を与えます。
主な特徴
- 軽量なコア - 依存ライブラリはUnderscore.jsのみ(DOM操作にはjQueryやZeptoを併用可能)で、本体は1ファイルに収まる小ささです
- イベント駆動のModel -
Modelの属性が変わるとchangeイベントが発火し、View側でその変化を検知して再描画できます - 柔軟性の高さ - Reactのような「決まった書き方」を強制しないため、既存のjQueryベースの資産に段階的に組み込みやすい構造です
インストール
npmを使う場合は次のコマンドでインストールできます。
npm install backbone underscore
CDN経由で読み込む場合は、Underscore.js(またはLodash)を先に読み込む必要があります。
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.8/underscore-min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/backbone@1.6.1/backbone-min.js"></script>
Backboneのサンプルを動かす
以下は入力フォームと連動したBackbone.Modelのサンプルです。テキストを入力するたびに
model.set()が呼ばれ、changeイベント経由で画面下部の表示が更新されます。
またmodel.get()で現在値を取り出し、validateメソッドで簡易バリデーションも行っています。
要点となる部分だけを抜き出すと、次のようになります。
const Task = Backbone.Model.extend({
defaults: { title: '', done: false },
validate(attrs) {
if (attrs.title.length === 0) return 'titleは必須です'
},
})
const task = new Task()
task.on('change:title', (model, value) => {
console.log('titleが変更されました:', value)
})
task.set({ title: '牛乳を買う' })
console.log(task.get('title')) // '牛乳を買う'
実際に動かせるものが下です。入力欄を空にするとバリデーションエラーが表示され、
文字を入れると即座にchangeイベントが発火して結果表示が切り替わります。
このサンプルから分かるように、Backbone.Modelは値を保持するだけでなく、
set()のたびにvalidateを通し、changeイベントで購読者に通知する仕組みを
標準で持っています。validateの中身をattrs.title.length < 3のように変えると、
3文字未満でエラーになる挙動も簡単に試せます。
基本的な使い方
Backbone.jsの基本は「Modelを定義し、Viewで描画する」という流れです。
const Book = Backbone.Model.extend({
defaults: { title: '', author: '' },
})
const BookView = Backbone.View.extend({
tagName: 'li',
initialize() {
this.listenTo(this.model, 'change', this.render)
},
render() {
this.el.textContent = `${this.model.get('title')} / ${this.model.get('author')}`
return this
},
})
const book = new Book({ title: 'リーダブルコード', author: 'Dustin Boswell' })
const view = new BookView({ model: book })
document.body.appendChild(view.render().el)
ViewのinitializeでlistenToを使い、Modelの変更を監視している点がポイントです。
this.elはBackboneが自動生成するDOM要素で、tagNameを指定することでタグ名を変更できます。
実践的なユースケース
Collectionによる一覧管理
複数のModelをまとめて扱いたい場合はBackbone.Collectionを使います。
一覧の追加・削除・並び替えといった操作を、Model単体では扱えない単位でまとめられます。
todos.add()で追加、todos.where({ done: true })で条件抽出ができるように、
Collectionは配列的な操作をBackboneのイベントシステムに乗せて提供します。
項目をクリックするとdoneが反転し、changeイベント経由で件数表示も同期される点を確認してみてください。
Routerによるページ切り替え
SPA的な画面遷移を作りたい場合はBackbone.Routerを使います。
URLのハッシュ(#以降)とハンドラー関数を対応付け、ブラウザの戻る・進むにも追従します。
routesオブジェクトでURLパターンとメソッド名を対応付け、Backbone.history.start()で
ルーティングの監視を開始します。上部のリンクをクリックすると、ページ遷移なしに
#topや#aboutへURLが変わり、対応するメソッドが実行されるのが確認できます。
まとめ
Backbone.jsは、Modelが状態とイベントを持ち、Viewがそれを購読して描画し、
Collectionが複数のModelをまとめ、RouterがURLと状態を結びつける——という
シンプルな役割分担だけを提供するライブラリです。仮想DOMも状態管理ライブラリも
持たない分、規模は小さく学習コストも低いので、既存のjQueryプロジェクトに
構造を与えたいときや、フレームワークの内部動作を理解する題材としても役立ちます。
まずは今回のサンプルを手元で書き換えて、ModelのイベントがどうViewに伝わるかを
体感してみてください。