You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
*The Flux implementation discussed in this section is available here [github.com/krasimir/fluxiny](https://github.com/krasimir/fluxiny). Feel free to use it in a browser [directly](https://github.com/krasimir/fluxiny/tree/master/lib) or as a [npm dependency](https://www.npmjs.com/package/fluxiny).*
5
+
---
8
6
9
7
I'm obsessed by making my code simpler. I didn't say *smaller* because having less code doesn't mean that is simple and easy to work with. I believe that big part of the problems in the software industry come from the unnecessary complexity. Complexity which is a result of our own abstractions. You know, we (the programmers) like to abstract. We like placing things in black boxes and hope that these boxes work together.
10
8
11
-
[Flux](http://facebook.github.io/flux/) is an architectural design pattern for building user interfaces. It was introduced by Facebook at their [F8](https://youtu.be/nYkdrAPrdcw?t=568) conference. Since then, lots of companies adopted the idea and it seems like a good pattern for building front-end apps. Flux is very often used with [React](http://facebook.github.io/react/). Another library released by Facebook. I myself use React+Flux in my [daily job](http://trialreach.com/) and I could say that the simplicity is one of the main benefits. This combination helps creating apps faster and at the same time keeps the code well organized.
9
+
[Flux](http://facebook.github.io/flux/) is an architectural design pattern for building user interfaces. It was introduced by Facebook at their [F8](https://youtu.be/nYkdrAPrdcw?t=568) conference. Since then, lots of companies adopted the idea and it seems like a good pattern for building front-end apps. Flux is very often used with [React](http://facebook.github.io/react/). Another library released by Facebook. I myself use React+Flux/Redux in my [daily job](http://antidote.me/) and I could say that the simplicity is one of the main benefits. This combination helps creating apps faster and at the same time keeps the code well organized.
The main actor in this pattern is the **dispatcher**. It acts as a hub for all the events in the system. Its job is to receive notifications that we call **actions** and pass them to all the **stores**. The store decides if it is interested or not and reacts by changing its internal state. The change is passed to the **views** which are (in my case) React components. If we have to compare Flux to the well known MVC we may say that the store is similar to the model. It keeps the data and its mutations.
15
+
The main actor in this pattern is the *dispatcher*. It acts as a hub for all the events in the system. Its job is to receive notifications that we call *actions* and pass them to all the *stores*. The store decides if it is interested or not and reacts by changing its internal state. That change is triggering re-rendering of the *views* which are (in our case) React components. If we have to compare Flux to the well known MVC we may say that the store is similar to the model. It keeps the data and its mutations.
18
16
19
-
The actions are coming to the dispatcher either from the views or from other part of the system like services. For example a module that performs a HTTP request. When it receives the result it may fire an action saying that the request was successful and attach the received data.
17
+
The actions are coming to the dispatcher either from the views or from other part of the system like services. For example a module that performs a HTTP request. When it receives the result it may fire an action saying that the request was successful.
20
18
21
19
A wrong data flow is one of the biggest pitfalls in flux. For example, we may have an access to the store in our views but we should never call store methods that mutate its internal state. This should only happen via actions. Or we may end up with a store that receives an action and dispatches another one.
22
20
23
-
*(More or less the explanation above is based on my reading of the Flux's documentation and my day-to-day experience with the pattern. Have in mind that you may see other interpretations. And you better do :))*
24
-
25
-
## My two cents
26
-
27
-
As every other popular concept Flux also has some [variations](https://medium.com/social-tables-tech/we-compared-13-top-flux-implementations-you-won-t-believe-who-came-out-on-top-1063db32fe73). I decided to try and write my own. One of the main goals was to be as simple as possible. That's how [Fluxiny](https://github.com/krasimir/fluxiny) was born.
21
+
## Implementing a Flux architecture
28
22
29
-
In the next few sections we'll see how I created the library. Why is that small and how I ended up having the code as it is.
23
+
As every other popular concept Flux also has some [variations](https://medium.com/social-tables-tech/we-compared-13-top-flux-implementations-you-won-t-believe-who-came-out-on-top-1063db32fe73). Very often to understand something we have to implement it ourself. In the next few sections we will create a library that provides helpers for building the Flux pattern.
30
24
31
25
### The dispatcher
32
26
33
-
In most of the cases we need a single dispatcher. Because it acts as a glue for the rest of the system's parts it makes sense that we have only one. There are two inputs to the dispatcher - actions and stores. The actions are simply forwarded to the stores so we don't necessary have to keep them. The stores however should be tracked inside the dispatcher:
27
+
In most of the cases we need a single dispatcher. Because it acts as a glue for the rest of the parts it makes sense that we have only one. There are two inputs to the dispatcher - actions and stores. The actions are simply forwarded to the stores so we don't necessary have to keep them. The stores however should be tracked inside the dispatcher so we can loop through them:
The first thing that we notice is that we *expect* to see an `update` method in the passed stores. It will be nice to throw an error if such method is missing:
51
+
The first thing that we notice is that we *expect* to see an `update` method in the passed stores. It will be nice to throw an error if such method is not there:
58
52
59
53
```js
60
54
register:function (store) {
@@ -68,20 +62,20 @@ register: function (store) {
68
62
69
63
### Bounding the views and the stores
70
64
71
-
The next logical step is to connect our views to the stores so we rerender when the state in the stores is changed.
65
+
The next logical step is to connect our views to the stores so we re-render when the state in the stores is changed.
72
66
73
-

67
+

74
68
75
69
76
70
#### Using a helper
77
71
78
-
Some of the flux implementations available provide a helper function that does the job. For example:
72
+
Some of the flux implementations available out there provide a helper function that does the job. For example:
79
73
80
74
```js
81
75
Framework.attachToStore(view, store);
82
76
```
83
77
84
-
However, I don't quite like this approach. To make `attachStore` works we expect to see a specific API in the view and in the store. We kind of strictly define new public methods. Or in other words we say "Your views and store should have such APIs so we are able to connect them together". If we go down this road then we'll probably define our own base classes which could be extended so we don't bother the developer with Flux details. Then we say "All your classes should extend our classes". This doesn't sound good either because the developer may decide to switch to another Flux provider and he/she has to amend everything.
78
+
However, I don't quite like this approach. To make `attachStore` works we expect to see a specific API in the view and in the store. We kind of strictly define new public methods. Or in other words we say "Your views and store should have such APIs so we are able to wire them together". If we go down this road then we will probably define our own base classes which could be extended so we don't bother the developer with Flux details. Then we say "All your classes should extend our classes". This doesn't sound good either because the developer may decide to switch to another Flux provider and he/she has to amend everything.
85
79
86
80
#### With a mixin
87
81
@@ -98,7 +92,7 @@ That's a "nice" way to define behavior of existing React component. So, in theor
98
92
99
93
#### Using a context
100
94
101
-
Another technique that my answer to the question is React's [context](https://facebook.github.io/react/docs/context.html). It's a way to pass props to child components without the need to specify them in every level of the tree. Facebook suggests context in the cases where we have data that has to reach deeply nested components.
95
+
Another technique that may answer to the question is React's [context](https://facebook.github.io/react/docs/context.html). It's a way to pass props to child components without the need to specify them in every level of the tree. Facebook suggests context in the cases where we have data that has to reach deeply nested components.
102
96
103
97
> Occasionally, you want to pass data through the component tree without having to pass the props down manually at every level. React's "context" feature lets you do this.
That's an interesting pattern because it shifts the responsibilities. It's the view fetching data from the store and not the store pushing something to the view. This of course has its own pros and cons. It is nice because it makes the store dummy. A store that only mutates the data and says "Oh, my state is changed". It is not responsible for sending anything. The downside of this approach is maybe the fact that we have one more component (the wrapper) involved. We also need the three bits - view, store and consumer in one place to fulfill the connection.
143
+
That is an interesting pattern because it shifts the responsibilities. It is the view fetching data from the store and not the store pushing something to the view. This of course has its own pros and cons. It is nice because it makes the store dummy. A store that only mutates the data and says "Hey, my state is changed". It is not responsible for sending anything to anyone. The downside of this approach is maybe the fact that we have one more component (the wrapper) involved. We also need the three bits - view, store and consumer to be in one place so we can fulfill the connection.
150
144
151
145
#### My choice
152
146
@@ -166,7 +160,7 @@ register: function (store) {
166
160
167
161
By using `register` we keep a reference to the store inside the dispatcher. However, `register` returns nothing. And instead of nothing it may return a **subscriber** that will accept our consumer functions.
168
162
169
-

163
+

170
164
171
165
I decided to send the whole store to the consumer function and not the data that the store keeps. Like in the higher-order components pattern the view should say what it needs by using store's getters. This makes the store really simple and there is no trace of presentational logic.
172
166
@@ -189,7 +183,7 @@ register: function (store) {
189
183
}
190
184
```
191
185
192
-
The last bit in the story is how the store says that its internal state is changed. It's nice that we collect the consumer functions but right now there is no code that runs them.
186
+
The last bit in the story is how the store says that its internal state is changed. It's nice that we collect the consumer functions but right now there is no code that execute them.
193
187
194
188
According to the basic principles of the flux architecture the stores change their state in response of actions. In the `update` method we send the `action` but we could also send a function `change`. Calling that function should trigger the consumers:
195
189
@@ -222,7 +216,7 @@ dispatch: function (action) {
222
216
}
223
217
```
224
218
225
-
<small>*Notice how we push `change` together with `store` inside the `_stores` array. Later in the `dispatch` method we call `update` by passing the `action` and the `change` function.*</small>
219
+
*Notice how we push `change` together with `store` inside the `_stores` array. Later in the `dispatch` method we call `update` by passing the `action` and the `change` function.*
226
220
227
221
A common use case is to render the view with the initial state of the store. In the context of our implementation this means firing all the consumers at least once when they land in the library. This could be easily done in the `subscribe` method:
228
222
@@ -233,7 +227,7 @@ var subscribe = function (consumer, noInit) {
233
227
};
234
228
```
235
229
236
-
Of course sometimes this is not needed so we add a flag which is by default falsy. Here is the final version of our dispatcher:
230
+
Of course sometimes this is not needed so we added a flag which is by default falsy. Here is the final version of our dispatcher:
237
231
238
232
```js
239
233
varDispatcher=function () {
@@ -272,7 +266,7 @@ var Dispatcher = function () {
272
266
273
267
## The actions
274
268
275
-
You probably noticed that we didn't talk about the actions. What are they? My opinion is that they should be simple objects having two properties - `type` and `payload`:
269
+
You probably noticed that we didn't talk about the actions. What are they? The convention is that they should be simple objects having two properties - `type` and `payload`:
276
270
277
271
```js
278
272
{
@@ -284,9 +278,9 @@ You probably noticed that we didn't talk about the actions. What are they? My op
284
278
}
285
279
```
286
280
287
-
The `type` says what exactly the action is all about and the `payload` contains the information associated with the event. And in some cases we may leave the `payload` empty.
281
+
The `type` says what exactly the action is and the `payload` contains the information associated with the event. And in some cases we may leave the `payload` empty.
288
282
289
-
It's interesting that the `type` is well known in the beginning. We know what type of actions should be floating in our app, who is dispatching them and which of the stores is interested. Thus, we can apply [partial application](http://krasimirtsonev.com/blog/article/a-story-about-currying-bind) and avoid passing the action object here and there. For example:
283
+
It's interesting that the `type` is well known in the beginning. We know what type of actions should be floating in our app, who is dispatching them and which of the stores are interested. Thus, we can apply [partial application](http://krasimirtsonev.com/blog/article/a-story-about-currying-bind) and avoid passing the action object here and there. For example:
290
284
291
285
```js
292
286
varcreateAction=function (type) {
@@ -303,15 +297,16 @@ var createAction = function (type) {
303
297
`createAction` leads to the following benefits:
304
298
305
299
* We no more need to remember the exact type of the action. We now have a function which we call passing only the payload.
306
-
* We no more need an access to the dispatcher which is a huge benefit. Otherwise, think about how we have to pass it to every single place where we need to dispatch an action. In the end we don't have to deal with objects but with functions which is much nicer. The objects are *static* while the functions describe a *process*.
300
+
* We no more need an access to the dispatcher which is a huge benefit. Otherwise, think about how we have to pass it to every single place where we need to dispatch an action.
301
+
* In the end we don't have to deal with objects but with functions which is much nicer. The objects are *static* while the functions describe a *process*.
This approach for creating actions is actually really popular and functions like the one above are usually called **action creators**.
305
+
This approach for creating actions is actually really popular and functions like the one above are usually called *action creators*.
311
306
312
307
## The final code
313
308
314
-
In the section above we successfully hid the dispatcher while submitting actions. We may do it again for the store's registration:
309
+
In the section above we successfully hide the dispatcher while submitting actions. We may do it again for the store's registration:
315
310
316
311
```js
317
312
varcreateSubscriber=function (store) {
@@ -474,6 +469,6 @@ And that's it. Our view is subscribed to the store and it renders by default bec
474
469
475
470
### A live demo
476
471
477
-
A live demo could be seen in the JSBin below. If that's not enough and it seems too simple for you please checkout the example in [Fluxiny](https://github.com/krasimir/fluxiny) repository [here](https://github.com/krasimir/fluxiny/tree/master/example). It uses React as a view layer.
472
+
A live demo could be seen in the following JSBin [http://jsbin.com/koxidu/embed?js,output](http://jsbin.com/koxidu/embed?js,output). If that's not enough and it seems too simple for you please checkout the example in Fluxiny repository [https://github.com/krasimir/fluxiny/tree/master/example](https://github.com/krasimir/fluxiny/tree/master/example). It uses React as a view layer.
478
473
479
-
<aclass="jsbin-embed"href="http://jsbin.com/koxidu/embed?js,output">JS Bin on jsbin.com</a><scriptsrc="http://static.jsbin.com/js/embed.min.js?3.35.5"></script>
474
+
*The Flux implementation discussed in this section is available here [github.com/krasimir/fluxiny](https://github.com/krasimir/fluxiny). Feel free to use it in a browser [directly](https://github.com/krasimir/fluxiny/tree/master/lib) or as a [npm dependency](https://www.npmjs.com/package/fluxiny).*
0 commit comments