-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy path06s-reactivity.md.erb
107 lines (76 loc) · 6.65 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
---
title: Reaktywność
slug: reactivity
date: 0006/01/02
number: 6.5
sidebar: true
contents: o systemie zależności reaktywnego kodu Meteora.|jak rozumieć motywacje i jak czyni to kod deklaratywnym.|jak używać zaawansowanego kodu, który używa reaktywnych danych.
paragraphs: 20
---
Jeżeli kolekcje są jądrem Metora, to *reaktywność* jest warstwą, która robi to jądro użytecznym.
Kolekcje radykalnie zmieniają sposób w jaki Twoja aplikacja radzi sobie ze zmianą danych. Zamiast ręcznie sprawdzać zmiany danych (np. przez wołanie AJAX) i następnie wstawianie zmian do HTMLa, zmiany danych zamiast tego mogą przyjść w dowolnym momencie i być nieprzerwanie aplikowane do interfejsu użytkownika przez Meteora.
Poświęć chwilę na przemyślenie tego: za kurtyną, Meteor może zmieniać *jakąkolwiek* część twojego interfejsu użytkownika gdy zależna od niego kolekcja ulega zmianie.
*Imperatywnym* sposobem na osiągniecie tego byłoby użycie `.observe()`, funkcji kursora, która wywołuje callbacki gdy dokumenty pasujące do kursora ulegają zmianie. Moglibyśmy wtedy aplikować zmiany w DOM (renderowanym HTML naszej strony) za pomocą tych callbacków. Kod wynikowy wyglądałby mniej więcej tak:
~~~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();
}
});
~~~
Prawdopodobnie zorientowałeś się już, jak szybko zwiększy się poziom skomplikowania takiego kodu. Wyobraź sobie radzenie sobie ze zmianami *każdego atrybutu* posta i koniecznością zmiany skomplikowanego HTML w elementach `<li>` posta. Nie wspominając o szczególnych przypadkach, które mogą się pojawić gdy zaczniemy polegać na wielu źródłach informacji, które mogą zmieniać się w czasie rzeczywistym.
<% note do %>
### Kiedy *powinniśmy* używać `observe()`?
Używanie powyższego schematu jest czasami konieczne, szczególnie przy pracy z widgetami ze źródeł trzecich. Na przykład wyobraź sobie, że chcemy dodać lub usuwać znaczniki na mapie w czasie rzeczywistym bazując na danych znajdujących się w Kolekcji (powiedzmy, aby pokazać lokalizacje bieżąco zalogowanych użytkowników).
W takich przypadkach będziesz musiał używać callbacków `observe()` aby zmusić mapę do "rozmowy" z kolekcją Meteora i wiedzieć jak reagować na zmianę danych. Na przykład, polegalibyśmy na callbackach `added` i `removed` aby wołać funkcje API mapy `dropPin()` czy `removePin()`.
<% end %>
### Podejście deklaratywne
Meteor daje nam lepsze rozwiązanie: reaktywność, która jest samym jądrem podejścia **deklaratywnego**. Bycie deklaratywnym pozwala na zdefiniowanie związku między obiektami raz i poźniej poleganie na tym, że będą automatycznie synchronizowane zamiast ustawiać akcje reagujące na każdą możliwą zmianę.
Jest to bardzo mocny koncept, ponieważ system reagujący w czasie rzeczywistym ma wiele wejść, które mogą zmieniać się w nieoczekiwanych momentach. Przez deklaratywne określenie jak renderujemy bazowane na HTML lub jakiekolwiek inne źródła danych o które się troszczymy, Meteor może przejąć pracę monitorowania źródeł danych i w sposób niewidoczny uaktualniać interfejs użytkownika.
Podsumowując to wszystko, zamiast myśleć o kolejnych callbackach `observe`, Meteor pozwala nam napisać:
~~~html
<template name="postsList">
<ul>
{{#each posts}}
<li>{{title}}</li>
{{/each}}
</ul>
</template>
~~~
I następnie otrzymać listę postów za pomocą:
~~~js
Template.postsList.helpers({
posts: function() {
return Posts.find();
}
});
~~~
Za kulisami Meteor podłącza callbacki `observe()` za nas przerenderowując odpowiednie sekcje HTML po zmianie reaktywnego źródła danych.
### Śledzenie zależności w Meteorze: Komputacje
Podczas gdy Meteor jest reaktywnym frameworkiem, działającym w trybie rzeczywistym, tylko *częściowo* kod samego Meteora jest reaktywny. Jeżeli byłby w całości reaktywny, cała aplikacja uruchamiała by się ponownie po każdej zmianie danych. Zamiast tego, reaktywność jest ograniczona do konkretnych obszarów kodu i nazywamy te obszary **komputacjami**.
Innymi słowy, komputacja jest blokiem kodu wykonywanym po każdej zmianie reaktywnego źródła danych. Jeżeli masz reaktywne źródło danych (na przykład zmienną Session) i chciałbyś reaktywnie na nią reagować, potrzebujesz ustawić odpowiednią komputację, która się tym zajmie.
Zauważ, że zwykle nie musisz tego robić jawnie, ponieważ Meteor daje domyślnie osobną specjalną komputację każdemu szablonowi, który renderuje (oznacza to, że kod w helperach szablonów i callbackach jest domyślnie reaktywny).
Każde reaktywne źródło danych śledzi wszystkie komputacje, które go używają, tak aby mogło same dać im znać, gdy jego wartość ulegnie zmianie. Aby to osiągnąć, woła funkcję `invalidate()` komputacji.
Komputacje są z reguły ustawiane po to, aby przeliczyć zawartość danych podczas weryfikacji i dzieje się tak również w komputacjach szablonu (dodatkowo komputacje szablonu próbują kilku sztuczek, aby bardziej widajnie przerysować stronę). Mimo, że możesz mieć większą kontrolę nad komputacją podczas wykonywania `invalidate`, to większość czasu będziesz potrzebował domyślnych ustawień.
### Ustawianie komputacji
Teraz skoro rozumiemy teorię komputacji, implementacja ich będzie nieproporcjonalnie łatwiejsza niż teoria. Używamy po prostu funkcji `Deps.autorun` aby umieścić blok kodu w komputacji i uczynić go reaktywnym:
~~~js
Deps.autorun(function() {
console.log('There are ' + Posts.find().count() + ' posts');
});
~~~
Za kulisami, `autorun` tworzy komputację i podłącza ją w odpowiednie miejsce, aby była wykonywana za każdym razem, gdy zmienia się źródło danych na którym zależy. Ustawiliśmy właśnie bardzo prostą komputację, która wypisuje w konsoli liczbę postów. Ponieważ `Posts.find()` jest reaktywnym źródłem danych, zatroszczy się o przekazanie komputacji, aby została wykonana za każdym razem, gdy liczba postów ulegnie zmianie.
~~~js
> Posts.insert({title: 'New Post'});
There are 4 posts.
~~~
Końcowym rezultatem tego jest to, że możemy pisać kod, który używa reaktywnych źródeł danych w bardzo naturalny sposób, wiedząc, że za kulisami system zależności we właściwym momencie zatroszczy się o uruchomienie kodu.