-
Notifications
You must be signed in to change notification settings - Fork 4
/
06s-reactivity.md.erb
111 lines (79 loc) · 8.33 KB
/
06s-reactivity.md.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
---
title: Tương tác lại
slug: reactivity
date: 0006/01/02
number: 6.5
sidebar: true
contents: Học về hệ thống code phụ thuộc tương tác lại.|Hiểu được động cơ và làm thế nào để khai báo code.|Học cách sử dụng code cấp cao để dùng dữ liệu tương tác lại.
paragraphs: 21
---
Nếu như Collection là tính năng lõi của Meteor, thì **tương tác lại** (reactivity) là lớp vỏ làm cho tính năng đó trở nên hữu ích.
Collection biến đổi tận gốc cách ứng dụng giải quyết vấn đề dữ liệu thay đổi. Thay vì phải kiểm tra dữ liệu thay đổi bằng tay (ví dụ như là thông qua lệnh gọi AJAX) và sau đó ráp nối lại những thay đổi đó vào HTML, việc thay đổi của dữ liệu có thể diễn ra tại bất kỳ thời điểm nào và được ghép vào giao diện người dùng của bạn một cách liền mạch với Meteor.
Hãy dành một chút thời gian để suy nghĩ về nó: phía sau màn hình, Meteor có khả năng thay đổi *bất kỳ* phần nào của giao diện người dùng khi mà collection phía bên dưới được cập nhật.
*Mệnh lệnh* để làm điều đó sẽ là dùng `.observe()`, một hàm con trỏ khởi động callback khi mà bản ghi so khớp với con trỏ đó thay đổi. Chúng ta có thể sau đó, thay đổi trên DOM (HTML được dịch của ứng dụng web) thông qua callback. Đoạn code kết quả sẽ như sau:
~~~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();
}
});
~~~
Bạn có thể đã nhận ra rằng đoạn code như trên sẽ nhanh chóng trở nên phức tạp. Thử tưởng tượng việc dàn xếp với thay đổi từ *mỗi thuộc tính* của bài post, và phải thay đổi HTML phức tạp với tag `<li>` của bài post. Không kể tới những trường hợp phức tạp tiềm ẩn có thể xảy ra khi chúng ta bắt đầu sử dụng thông tin trên nhiều nguồn mà chúng đều có thể thay đổi thời gian thực.
<% note do %>
### Khi nào chúng ta *Nên* dùng `observe()`?
Dùng kiểu mẫu như trên đôi khi có thể cần thiết, đặc biệt là khi giải quyết với widget từ nguồn thứ ba. Ví dụ, hãy tưởng tượng chúng ta muốn thêm hoặc xoá những điểm ghim trên bản đồ theo thời gian thực dựa trên dữ liệu Collection (để hiển thị địa điểm của người dùng đang log in).
Trong trường hợp đó, bạn sẽ cần dùng callback `observe()` để cho bản đồ "nói chuyện" với collection Meteor và biết làm thế nào để phản ứng lại dữ liệu thay đổi. Ví dụ, bạn sẽ dựa vào callback `added` và `removed` để gọi method `dropPin()` hoặc `removePin()` của API bản đồ.
<% end %>
### Cách tiếp cận khai báo
Meteor cung cấp cho chúng ta một cách tốt hơn: khả năng phản ứng, tức là cách tiếp cận **khai báo** trong phần lõi của nó. Khai báo để cho chúng ta khai báo mối quan hệ giữa các object, và biết được chúng sẽ được giữ đồng bộ, thay vì phải đặc tả cho từng trường hợp thay đổi.
Đây là một khái niệm có sức mạnh, bởi vì một hệ thống thời gian thực có nhiều đầu vào có thể bị thay đổi ở những thời điểm không đoán trước được. Bằng việc khai báo trạng thái làm thế nào để ráp HTML dựa trên bất kỳ nguồn dữ liệu tương tác lại nào chúng ta quan tâm đên, Meteor có thể đảm đương được công việc theo dõi những nguồn này và nhận trách nhiệm làm công việc hỗn độn là giữ cho giao diện người dùng được cập nhật.
Tất cả điều ở trên muốn nói rằng, thay vì việc nghĩ đến callback `observe`, Meteor để chúng ta viết:
~~~html
<template name="postsList">
<ul>
{{#each posts}}
<li>{{title}}</li>
{{/each}}
</ul>
</template>
~~~
Và sau đó lấy danh sách post với:
~~~js
Template.postsList.helpers({
posts: function() {
return Posts.find();
}
});
~~~
Phía sau màn hình, Meteor bọc lại `observe()` callback cho chúng ta, và vẽ lại những phần HTML thích đáng khi dữ liệu tương tác lại thay đổi.
### Theo dấu phụ thuộc trong Meteor: tính toán số (computation)
Trong khi Meteor là một framework thời gian thực, tương tác lại, không phải *tất cả* code bên trong Meteor đều có tính chất tương tác lại. Nếu điều đó xảy ra, toàn bộ ứng dụng của bạn sẽ chạy lại mỗi khi có bất kỳ thay đổi nào. Thay vào đó, tương tác lại hạn chế tới những vùng đặc biệt trong mã code của bạn, chúng ta có thể gọi chúng là những vùng **tính toán số**
Nói cách khác, một tính toán số là một khối code mà được chạy mỗi khi mà có một nguồn dữ liệu tương tác lại mà nó phụ thuộc vào thay đổi. Nếu bạn có một nguồn dữ liệu tương tác lại (ví dụ, một biến Session) và muốn đáp lại một cách tương tác lại với nó, bạn cần phải thiết lập tính toán số cho nó.
Chú ý rằng thường thì bạn không cần phải làm việc này bởi vì Meteor đã cho mỗi template và helper tính toán số đặc biệt của nó (nghĩa là bạn có thể chắc rằng template sẽ phản xạ một cách tương tác tới nguồn dữ liệu của chúng)
Mỗi nguồn dữ liệu tương tác lại theo dõi tất cả tính toán số mà sử dụng nó để nó có thể biết được chúng mỗi khi giá trị mà nó sở hữu thay đổi. Để làm điều đó, nó gọi hàm `invalidate()` đối với tính toán số.
Tính toán số thường được thiết lập để dễ dàng đánh giá lại nội dung của nó trong invalidation, và đây là thứ xảy ra với tính toán số của template (mặc dù tính toán số của template cũng làm một số xảo thuật để thử và vẽ lại trang một cách hiệu quả hơn). Mặc dù bạn cũng có thể có thêm quyền điều khiển đối với tính toán số trong invalidation nếu bạn muốn, trong thực hành điều này hầu như luôn là cách xử lý mà bạn sẽ sử dụng.
### Thiết lập một tính toán số (computation)
Bây giờ bạn đã hiểu được học thuyết phía sau tính toán số, việc thiết lập sẽ làm cho nó dễ hiểu hơn. Chúng ta sẽ dùng hàm `Tracker.autorun` để bao bọc một khối code tính toán và làm cho nó tương tác lại:
~~~js
Meteor.startup(function() {
Tracker.autorun(function() {
console.log('There are ' + Posts.find().count() + ' posts');
});
});
~~~
Chú ý rằng chúng ta phải cho khối `Tracker` bọc trong khối `Meteor.startup()` để chắc chắn rằng nó chỉ chạy duy nhất một lần khi Meteor đã kết thúc việc nạp collection `Posts`.
Phía sau màn hình, `autorun` sẽ tạo ra một tính toán số, và làm cho nó được tính lại mỗi khi nguồn dữ liệu mà nó phụ thuộc vào thay đổi. Chúng ta vừa thiết lập một tính toán số rất đơn giản đó là logs lại số lượng post ra console. Vì `Posts.find()` là một nguồn dữ liệu tương tác lại, nó sẽ đảm nhiệm vai trò báo cho tính toán số tính lại giá trị mỗi khi số lượng posts thay đổi.
~~~js
> Posts.insert({title: 'New Post'});
There are 4 posts.
~~~
Kết quả của tất cả điều này là chúng ta có thể viết code mà dùng dữ liệu tương tác lại một cách rất tự nhiên, biết rằng ở phía sau màn hình, hệ thống phụ thuộc sẽ đảm nhiệm vai trò chạy lại mỗi khi đến thời điểm phù hợp.