OSDN Git Service

Regular updates
[twpd/master.git] / flux.md
1 ---
2 title: Flux architecture
3 category: React
4 ---
5
6 ## Architecture
7
8 * __Dispatchers__ receive *actions* that get dispatched to its listeners.
9
10 * __Stores__ are objects that store data, usually changed from a dispatcher listener.
11
12 * __Views__ are React components that listen to Store changes, or emit *actions* to the dispatcher.
13
14 ----
15
16 ## Dispatcher
17
18 ### Pub-sub
19 [A dispatcher][dispatcher] emits events (`.dispatch()`) to its listeners (`.register(fn)`).
20
21 ```js
22 var Dispatcher = require('flux').Dispatcher;
23
24 d = new Dispatcher();
25
26 // send
27 d.dispatch({ action: 'edit', ... };
28
29 // receive
30 token = d.register(function (payload) {
31   payload.action === 'edit'
32 })
33 ```
34
35 ### Ensuring proper order
36
37 With multiple listeners, you can ensure one is fired after another using `.waitFor()`.
38
39 ```js
40 token1 = d.register(...);
41
42 token2 = d.register(function (payload) {
43
44   // ensure receiver 1 is fired before this
45   d.waitFor([ token1 ]);
46   
47   // process here
48 })
49 ```
50
51 ### Subclassing
52
53 [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) is the preferred way to subclass Dispatcher (think `$.extend`).<br>
54 You can also make *action creators*, which are shortcuts for `dispatch()`.
55
56 ```js
57 var Dispatcher = require('flux').Dispatcher;
58 var assign = require('object-assign');
59
60 var AppDispatcher = assign({}, Dispatcher.prototype, {
61
62   // action creator
63   handleViewAction(action) {
64     this.dispatch({
65       source: 'VIEW_ACTION',
66       action: action
67     })
68   } 
69
70 })
71 ```
72
73 ----
74
75 ## Stores
76
77 ### Plain objects
78 Stores are just like objects.
79
80 ```js
81 var TodoStore = { list: [] };
82 ```
83
84 ### Events
85 Sometimes they're eventemitters, too. Usually it's used to emit `change` events for views to pick up.
86
87 ```js
88 var TodoStore = assign({}, EventEmitter.prototype, {
89   ...
90 });
91
92 TodoStore.emit('change');
93 TodoStore.on('change', function () { ... });
94 ```
95
96 ### Model logic
97 Logic can sometimes belong in stores.
98
99 ```js
100 {
101   isAllActive() {
102     return this.list.every(item => item.active);
103   }
104 }
105 ```
106
107
108 ----
109
110 ## Stores and dispatchers
111
112 ### Instantiate
113 Make a Dispatcher and Stores.
114
115 ```js
116 d = new Dispatcher();
117 TabStore = { tab: 'home' };
118 ```
119
120 ### Updating data
121 Dispatch events to alter the store.
122
123 ```js
124 d.dispatch({ action: 'tab.change', tab: 'timeline' });
125
126 d.register(function (data) {
127   if (data.action === 'tab.change') {
128     TabStore.tab = data.tab;
129   }
130 });
131 ```
132
133 ----
134
135 ## With Views
136
137 ### Listen to dispatchers
138 Views (React Components) can listen to Dispatchers.
139
140 ```js
141 var TodoApp = React.createClass({
142
143   componentDidMount() {
144     this.token = AppDispatcher.register((payload) => {
145       switch (payload.action) {
146         case 'tab.change':
147           this.render();
148           // ...
149       }
150     });
151   },
152   
153   componentDidUnmount() {
154     AppDispatcher.unregister(this.token);
155   }
156   
157 });
158 ```
159
160 ### Listen to Stores
161 Or to Stores's `change` events.
162
163 ```js
164 {
165   componentDidMount() {
166     TodoStore.on('change', this.onChange);
167   },
168   
169   componentDidUnmount() {
170     TodoState.removeListener('change', this.onChange);
171   },
172   
173   onChange(data) {
174     // ...
175   }
176 }
177 ```
178
179 ----
180
181 ### Also see
182
183 * [Dispatcher API][dispatcher]
184 * [React cheatsheet](react.html)
185 * [Dispatcher.js source](https://github.com/facebook/flux/blob/master/src/Dispatcher.js)
186 * [Flux-todomvc explanation](https://github.com/facebook/flux/tree/master/examples/flux-todomvc)
187
188 [dispatcher]: http://facebook.github.io/flux/docs/dispatcher.html