---
title: 響應式
slug: reactivity
date: 0006/01/02
number: 6.5
points: 5
sidebar: true
photoUrl: http://www.flickr.com/photos/ikewinski/9632550278/
photoAuthor: Mike Lewinski
contents: 學習 Meteor 響應式代碼依賴系統。|理解它的原理以及它如何聲明代碼。|學習使用高級代碼來調用響應式數據。
paragraphs: 20
---
如果說集合是 Meteor 的核心功能,那么**響應式**可以能讓這個核心功能更強大。
集合從根本上改變你的應用程序的數據處理方式。從而不必手動檢查數據更改(例如,通過一個 AJAX 調用),再根據這些變化去修改 HTML 頁面,Meteor 可以隨時檢測到數據的更改,并將它無縫地應用到你的用戶界面上。
讓我們思考一下:在后臺,當底層的數據集合被更新以后, Meteor 能夠馬上修改用戶界面的**任何**部分。
這個實時性的方法是通過使用 `.observe()` ,當指向數據的指針發生改變時就會觸發回調。我們可以通過這些回調去更改 DOM (我們的網頁呈現的 HTML )。就像這樣的代碼:
~~~js
Posts.find().observe({
added: function(post) {
// when 'added' callback fires, add HTML element
$('ul').append('<li id="' + post._id + '">' + post.title + '</li>');
},
changed: function(post) {
// when 'changed' callback fires, modify HTML element's text
$('ul li#' + post._id).text(post.title);
},
removed: function(post) {
// when 'removed' callback fires, remove HTML element
$('ul li#' + post._id).remove();
}
});
~~~
可能你已經知道這樣的代碼是如何把復雜的事情快速地進行處理。想象一下如果我們去修改帖子的**任何一個屬性**,就會伴隨著頁面中帖子 `<li>` 標簽的更改。當我們開始依賴于更多個數據信息的時候,甚至還可以進行更為復雜的處理,這些都能實時地進行。
<% note do %>
### 我們應該什么時候去使用 `observe()` ?
使用上述的模式有時候很有必要的,尤其是在處理第三方小部件的時候。比如,假設我們想要基于集合數據去實時添加或刪除在地圖上的位置(也就是說顯示當前登錄用戶的位置)。
在這種情況下,為了讓地圖能跟 Meteor 的集合進行“交談”,你就需要使用 `observe()` 的回調方法去應對數據變化。例如,你需要依賴其中 `added` 和 `removed` 的回調方法去調用地圖 API 中的 `dropPin()` 或 `removePin()` 方法。
<% end %>
### 聲明式方法
Meteor 為我們提供了一個更好的辦法:聲明式方法,它的核心就是響應式。這種聲明讓我們定義了對象之間的關系,并讓他們保持同步,而我們就不必為每個的可能發生的修改去指定相應的行為。
這是一個強大的概念,因為有許多實時性的輸入,都可能發生在我們不可預測的時間中。通過聲明式方法去聲明我們該如何基于響應式數據去呈現 HTML ,這樣 Meteor 就可以完成對這些數據的監控工作,并且把用戶界面直接與數據進行綁定。
總的來說,去代替 `observe` 的回調,Meteor 可以讓我們這樣寫:
~~~html
<template name="postsList">
<ul>
{{#each posts}}
<li>{{title}}</li>
{{/each}}
</ul>
</template>
~~~
然后獲取我們的帖子列表:
~~~js
Template.postsList.helpers({
posts: function() {
return Posts.find();
}
});
~~~
在后臺,其實 Meteor 替我們使用了 `observe()` 的回調方法,并當響應式數據被更改的時候,對相關頁面進行重新的渲染。
### Meteor 的依賴跟蹤:Computations
Meteor 是一個實時性、響應式的框架,但并不是**所有**的代碼在 Meteor App 里面都是響應式的。如果是這樣,當有任何數據發生改變時,你的 App 都會自動進行重新運行。相反,響應式只是在特定區域的代碼中發生,我們稱這些區域為 **Computations** 。
換句話說, Computations 代碼塊是根據響應式數據的變化去運行。如果你有一個響應式數據源(例如,一個 Session 變量)并且希望及時去響應它,你需要建立一個 Computations。
請注意,你一般不需要顯式地做到這一點,因為 Meteor 已經讓每個模板去呈現它自己的 Computation (意思就是模板 Helper 中的代碼和回調函數默認都是響應式的)。
Computations 用到的響應式數據源都會被它跟蹤,這樣就可以知道響應式數據什么時候發生變化。這是通過 Computations 中的 `invalidate()` 方法實現的。
Computations 一般只是簡單地用來判斷頁面上的無效內容,這通常是發生在模板的 Computations(盡管模板 Computations 可能也會去做一些讓頁面更有效的工作)。當然如果你需要,你也可以使用更多 Computations 的功能,不過在實際中可能比較少用到。
### 建立一個 Computations
現在我們去理解一下 Computations 背后的工作原理,實際上要設置一個 Computations 是出乎意料的簡單。我們只需要在 `Tracker.autorun` 方法中加上需要的代碼塊,讓它變成響應式的 Computations :
~~~js
Meteor.startup(function() {
Tracker.autorun(function() {
console.log('There are ' + Posts.find().count() + ' posts');
});
});
~~~
注意我們需要把 `Tracker` 代碼塊放進 `Meteor.startup()` 塊中,來確保它在 Meteor 完成加載 `Posts` 集合后只運行一次。
在后臺,`autorun` 會創建一個 Computation ,當數據源發生變化的時候就會自動重新運行。這樣我們就建立了一個非常簡單的 Computation ,去把帖子的數量輸出到控制臺上。因為 `Posts.find()` 是一個響應式數據源,它將負責告訴 Computation 每次帖子數量發生變化的時候去重新運行。
~~~js
> Posts.insert({title: 'New Post'});
There are 4 posts.
~~~
綜上所述,我們可以把響應式數據通過一種很自然的方式與代碼進行綁定,這樣后臺的依賴系統將會在合適的時間去重新運行這段代碼。