-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path14500787263408.html
4135 lines (3082 loc) · 197 KB
/
14500787263408.html
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>
[Sahat **Yalkabov**][1] - Junkman
</title>
<link href="atom.xml" rel="alternate" title="Junkman" type="application/atom+xml">
<link rel="stylesheet" href="asset/css/foundation.min.css" />
<link rel="stylesheet" href="asset/css/docs.css" />
<script src="asset/js/vendor/modernizr.js"></script>
<script src="asset/js/vendor/jquery.js"></script>
<script src="asset/highlightjs/highlight.pack.js"></script>
<link href="asset/highlightjs/styles/github.css" media="screen, projection" rel="stylesheet" type="text/css">
<script>hljs.initHighlightingOnLoad();</script>
<script type="text/javascript">
function before_search(){
var searchVal = 'site:panlw.github.io ' + document.getElementById('search_input').value;
document.getElementById('search_q').value = searchVal;
return true;
}
</script>
</head>
<body class="antialiased hide-extras">
<div class="marketing off-canvas-wrap" data-offcanvas>
<div class="inner-wrap">
<nav class="top-bar docs-bar hide-for-small" data-topbar>
<section class="top-bar-section">
<div class="row">
<div style="position: relative;width:100%;"><div style="position: absolute; width:100%;">
<ul id="main-menu" class="left">
<li id=""><a target="self" href="index.html">Home</a></li>
<li id=""><a target="_self" href="archives.html">Archives</a></li>
</ul>
<ul class="right" id="search-wrap">
<li>
<form target="_blank" onsubmit="return before_search();" action="http://google.com/search" method="get">
<input type="hidden" id="search_q" name="q" value="" />
<input tabindex="1" type="search" id="search_input" placeholder="Search"/>
</form>
</li>
</ul>
</div></div>
</div>
</section>
</nav>
<nav class="tab-bar show-for-small">
<a href="javascript:void(0)" class="left-off-canvas-toggle menu-icon">
<span> Junkman</span>
</a>
</nav>
<aside class="left-off-canvas-menu">
<ul class="off-canvas-list">
<li><a href="index.html">HOME</a></li>
<li><a href="archives.html">Archives</a></li>
<li><a href="about.html">ABOUT</a></li>
<li><label>Categories</label></li>
<li><a href="Infra.html">Infra</a></li>
<li><a href="Coding.html">Coding</a></li>
<li><a href="Modeling.html">Modeling</a></li>
<li><a href="Archtecting.html">Archtecting</a></li>
</ul>
</aside>
<a class="exit-off-canvas" href="#"></a>
<section id="main-content" role="main" class="scroll-container">
<script type="text/javascript">
$(function(){
$('#menu_item_index').addClass('is_active');
});
</script>
<div class="row">
<div class="large-8 medium-8 columns">
<div class="markdown-body article-wrap">
<div class="article">
<h1>[Sahat **Yalkabov**][1]</h1>
<div class="read-more clearfix">
<span class="date">2015/12/14</span>
<span>posted in </span>
<span class="posted-in"><a href='Node.js.html'>Node.js</a></span>
<span class="comments">
</span>
</div>
</div><!-- article -->
<div class="article-content">
<ul>
<li><a href="/projects" title="Projects">Projects</a></li>
<li><a href="https://github.com/sahat" title="GitHub">GitHub</a></li>
</ul>
<h1 id="toc_0">Create a character voting app using React, Node.js, MongoDB and Socket.IO</h1>
<p>In this tutorial we are going to build a character voting app (inspired by Facemash) for EVE Online - a massively multiplayer online game. You will learn how to build a REST API with <strong>Node.js</strong>, save and retrieve data from <strong>MongoDB</strong>, track online visitors in real-time using <strong>Socket.IO</strong>, build a single-page app experience using <strong>React</strong> + <strong>Flux</strong> with server-side rendering and then finally deploy it to the cloud. </p>
<p>Published on <strong>July 21, 2015</strong></p>
<p>__ Please consider disabling your ad blocker on this site. </p>
<p>__ read </p>
<h3 id="toc_1">Update Notice 2 (November 12, 2015)</h3>
<p>Tutorial has been updated to use <a href="https://medium.com/@malyw/how-to-update-babel-5-x-6-x-d828c230ec53"><strong>Babel 6.0</strong></a> and <a href="https://github.com/rackt/react-router/releases/tag/v1.0.0"><strong>React Router 1.0</strong></a>. For detailed tutorial updates see <u>November 12, 2015</u> notes below.</p>
<h3 id="toc_2">Update Notice 1 (October 19, 2015)</h3>
<p>Tutorial has been updated to use <strong>React 0.14</strong> and <strong>React Router 1.0-rc3</strong> that introduced breaking changes. For detailed tutorial updates see <u>October 19, 2015</u> notes below.</p>
<h2 id="toc_3">Table of Contents</h2>
<ul>
<li>Overview</li>
<li>Step 1. New Express Project</li>
<li>Step 2. Build System</li>
<li>Step 3. Project Structure</li>
<li>Step 4. ES6 Crash Course</li>
<li>Step 5. React Crash Course</li>
<li>Step 6. Flux Architecture Crash Course</li>
<li>Step 7. React Routes (Client-Side)</li>
<li>Step 8. React Routes (Server-Side)</li>
<li>Step 9. Footer and Navbar Components</li>
<li>Step 10. Socket.IO - Real-time User Count</li>
<li>Step 11. Add Character Component</li>
<li>Step 12. Database Schema</li>
<li>Step 13. Express API Routes (1 of 2)</li>
<li>Step 14. Home Component</li>
<li>Step 15. Express API Routes (2 of 2)</li>
<li>Step 16. Character (Profile) Component</li>
<li>Step 17. Top 100 Component</li>
<li>Step 18. Stats Component</li>
<li>Step 19. Deployment</li>
<li>Step 20. Additional Resources</li>
<li>In Closing</li>
</ul>
<h2 id="toc_4">Overview</h2>
<p>In this tutorial we are going to build a character voting app (inspired by <u>Facemash</u> and <u>Hot or Not</u>) for <a href="http://www.eveonline.com/">EVE Online</a> - a massively multiplayer online game. Be sure to play this awesome soundtrack below to get yourself in the mood for this epicly long tutorial.</p>
<p>While listening to this soundtrack, imagine yourself mining asteroid belts in deep space while keeping a lookout for pirates on the radar, researching propulsion system blueprints at the station's facility, manufacturing spaceship components for capital ships, placing buy & sell orders on the entirely player-driven market where supply and demand govern the game economics, hauling trade goods from a remote solar system in a massive freighter, flying blazingly fast interceptors with a microwarpdrive or powerful battleships armored to the teeth, optimizing extraction efficiency of rare minerals from planets, or fighting large-scale battles with thousands of players from multiple alliances. That is <strong>EVE Online</strong>.</p>
<p>Each player in EVE Online has a 3D avatar representing their character. This app is designed for ranking those avatars. Anyway, your goal here is to learn about Node.js, React and Flux, not EVE Online. But I will say this: "Having an interesting tutorial project is just as important, if not more so, than the main subject of the tutorial". The only reason I built the original <a href="http://www.newedenfaces.com/">New Eden Faces</a> app is to learn __Backbone.js and the only reason I built the <a href="https://github.com/sahat/tvshow-tracker">TV Show Tracker</a> app is so that I could learn __AngularJS. To me, either one of these projects is far more interesting than a simple todo app that everyone seems to be using these days.</p>
<p>One thing that I have learned — between screencasts, books and training videos, nothing is more effective than building a small project that you are passionate about to learn a new technology.</p>
<p><img src="/images/blog/Screenshot%202015-03-31%2023.05.36.png" alt=""/></p>
<ul>
<li><a href="https://github.com/sahat/newedenfaces-react">__ GitHub Source Code</a></li>
</ul>
<p>In the same spirit as my previous tutorials (<a href="http://sahatyalkabov.com/create-a-tv-show-tracker-using-angularjs-nodejs-and-mongodb/">TV Show Tracker</a> and <a href="https://hackhands.com/building-instagram-clone-angularjs-satellizer-nodejs-mongodb/">Instagram Clone</a>), this is a step by step full-stack JavaScript tutorial where we build a complete app from the ground up.</p>
<p>Note</p>
<p>This is a remake of the original <a href="http://www.newedenfaces.com/">New Eden Faces</a> (2013) project, which was my first ever single-page application written in Backbone.js. It has been running in production on <a href="https://www.openshift.com/">OpenShift</a> with Node.js 0.8.x for over 2 years now. </p>
<p>I usually make as few assumptions as possible about a particular topic, which is why my tutorials are so lengthy, but having said that, you need to have at least some prior experience with client-side JavaScript frameworks and Node.js to get the most out of this tutorial.</p>
<p>Before proceeding, you will need to download and install the following tools:</p>
<ol>
<li>__ <a href="https://nodejs.org/">Node.js</a></li>
<li>__ <a href="http://bower.io/">Bower</a></li>
<li>__ <a href="https://www.mongodb.org/downloads">MongoDB</a></li>
<li>__ <a href="https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md">gulp</a></li>
<li>__ <a href="https://github.com/remy/nodemon#nodemon">nodemon</a></li>
</ol>
<h2 id="toc_5">Step 1. New Express Project</h2>
<p>Create a new directory <strong>__newedenfaces</strong>. Inside, create 2 empty files <u>package.json</u> and <u>server.js</u> using your favorite text editor or using the command line:</p>
<p><img src="/images/blog/Screenshot%202015-03-22%2004.50.51.png" alt=""/></p>
<p><strong>July 22, 2015 Update:</strong> I am using the default Terminal app in Mac OS X with <a href="https://github.com/stephenway/monokai.terminal">Monokai</a> theme and <a href="https://github.com/oh-my-fish/oh-my-fish">oh-my-fish</a> framework for the <a href="http://fishshell.com/">Fish</a> shell.</p>
<p>Open <u>package.json</u> and paste the following:</p>
<pre><code>{
"name": "newedenfaces",
"description": "Character voting app for EVE Online",
"version": "1.0.0",
"repository": {
"type": "git",
"url": "https://github.com/sahat/newedenfaces-react"
},
"main": "server.js",
"scripts": {
"start": "node server.js",
"watch": "nodemon server.js"
},
"babel": {
"presets": ["es2015", "react"]
},
"dependencies": {
"alt": "^0.17.8",
"async": "^1.5.0",
"body-parser": "^1.14.1",
"colors": "^1.1.2",
"compression": "^1.6.0",
"express": "^4.13.3",
"history": "^1.13.0",
"mongoose": "^4.2.5",
"morgan": "^1.6.1",
"react": "^0.14.2",
"react-dom": "^0.14.2",
"react-router": "^1.0.0",
"request": "^2.65.0",
"serve-favicon": "^2.3.0",
"socket.io": "^1.3.7",
"swig": "^1.4.2",
"underscore": "^1.8.3",
"xml2js": "^0.4.15"
},
"devDependencies": {
"babel-loader": "^6.1.0",
"babel-core": "^6.1.19",
"babel-preset-es2015": "^6.1.18",
"babel-preset-react": "^6.1.18",
"babelify": "^7.2.0",
"bower": "^1.6.5",
"browserify": "^12.0.1",
"gulp": "^3.9.0",
"gulp-autoprefixer": "^3.1.0",
"gulp-concat": "^2.6.0",
"gulp-cssmin": "^0.1.7",
"gulp-if": "^2.0.0",
"gulp-less": "^3.0.3",
"gulp-plumber": "^1.0.1",
"gulp-streamify": "1.0.2",
"gulp-uglify": "^1.4.2",
"gulp-util": "^3.0.7",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.6.0"
},
"license": "MIT"
}
</code></pre>
<p><strong>October 19, 2015 Update:</strong> Updated package versions and added two new packages: <a href="https://www.npmjs.com/package/react-dom">react-dom</a> (as part of the React 0.14 changes) and <a href="https://www.npmjs.com/package/history">history</a> (as part of the React Router 1.0 changes).</p>
<p><img src="/images/babel-logo.svg" alt=""/></p>
<p><strong>November 12, 2015 Update:</strong> Added <code>babel</code> configuration presets (new in Babel 6.x). No longer uses <code>babel-node</code> command to start or watch the server, instead you can use <code>node</code> and <code>nodemon</code> commands directly. Updated existing packages, removed unused packages, added new Babel 6.x packages.</p>
<p>These are all the packages that we will be using in this project. Let's briefly go over each package.</p>
<p>Package Name Description</p>
<p><a href="https://github.com/goatslacker/alt">alt</a><br/>
Flux library for React.</p>
<p><a href="https://github.com/caolan/async">async</a><br/>
For managing asynchronous flow.</p>
<p><a href="https://github.com/expressjs/body-parser">body-parser</a><br/>
For parsing POST request data.</p>
<p><a href="https://github.com/marak/colors.js/">colors</a><br/>
Pretty console output messages.</p>
<p><a href="https://github.com/expressjs/compression">compression</a><br/>
Gzip compression.</p>
<p><a href="http://expressjs.com">express</a><br/>
Web framework for Node.js.</p>
<p><a href="https://github.com/rackt/history">history</a><br/>
Manage session history in browsers, used by react-router.</p>
<p><a href="http://mongoosejs.com/">mongoose</a><br/>
MongoDB ODM with validation and schema support.</p>
<p><a href="https://github.com/expressjs/morgan">morgan</a><br/>
HTTP request logger.</p>
<p><a href="http://facebook.github.io/react/">react</a><br/>
React.</p>
<p><a href="https://www.npmjs.com/package/react-dom">react-dom</a><br/>
React rendering, it is no longer bundled with React.</p>
<p><a href="https://github.com/rackt/react-router">react-router</a><br/>
Routing library for React.</p>
<p><a href="https://github.com/request/request">request</a><br/>
For making HTTP requests to EVE Online API.</p>
<p><a href="https://github.com/expressjs/serve-favicon">serve-favicon</a><br/>
For serving <u>favicon.png</u> icon.</p>
<p><a href="http://socket.io/">socket.io</a><br/>
To display how many users are online in real-time.</p>
<p><a href="http://paularmstrong.github.io/swig/">swig</a><br/>
To render the initial HTML template.</p>
<p><a href="http://underscorejs.org/">underscore</a><br/>
Helper JavaScript utilities.</p>
<p><a href="https://github.com/Leonidas-from-XIV/node-xml2js">xml2js</a><br/>
For parsing XML response from EVE Online API.</p>
<p>Run <code>npm install</code> in the Terminal to install the packages that we specified in the <u>package.json</u>.</p>
<p><img src="/images/blog/Screenshot%202015-03-22%2005.19.19.png" alt=""/></p>
<p>Note</p>
<p>If you are using Windows check out <a href="http://cmder.net/">cmder</a> console emulator. It is the closest thing to Mac OS X/Linux Terminal experience. </p>
<p>Open <u>server.js</u> and paste the following code. It's a very minimal Express application, just enough to get us started.</p>
<pre><code>var express = require('express');
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');
var app = express();
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
});
</code></pre>
<p>Note</p>
<p>Although we will be building the React app in ES6, I have decided to use ES5 here because this back-end code is mostly unchanged from when I built the original <a href="https://github.com/sahat/newedenfaces">New Eden Faces</a> app. Furthermore, if you are using ES6 for the first time, it won't be too overwhelming, since the Express app should still be familiar to you. </p>
<p>Next, create a new directory <strong>__public</strong>. This is where we are going to place <u>images</u>, <u>fonts</u>, compiled <u>CSS</u> and <u>JavaScript</u> files.</p>
<p><img src="/images/blog/Screenshot%202015-03-22%2005.41.53.png" alt=""/></p>
<p>Run <code>npm start</code> in the Terminal to make sure our Express app is working without any issues.</p>
<p>You should see <strong>Express server listening on port 3000</strong> message in the Terminal.</p>
<h2 id="toc_6">Step 2. Build System</h2>
<p>If you have been around in the web community at all, then you may have heard about <a href="http://browserify.org/">Browserify</a> and <a href="http://webpack.github.io/">Webpack</a> tools. If not, then consider what it would be like having to manually include all these <code><script></code> tags in a specific order, because one file may depend on another file which depends on another file.</p>
<p><img src="/images/blog/Screenshot%202015-06-20%2022.56.37.png" alt=""/></p>
<p>Additionally, we cannot use ECMAScript 6 directly in the browsers yet. Our code needs to be transformed by Babel into ECMAScript 5 before it can be served and interpreted by the browsers.</p>
<p>We will be using <a href="http://gulpjs.com/">Gulp</a> and <a href="http://browserify.org/">Browserify</a> in this tutorial instead of Webpack. I will not advocate for which tool is better or worse, but personally I found that Gulp + Browserify is more straightforward to me than an equivalent Webpack config file. I have yet to find a React boilerplate project with an easy to understand <u>webpack.config.js</u> file.</p>
<p>Create a new file <u>gulpfile.js</u> and paste the following code:</p>
<pre><code>var gulp = require('gulp');
var gutil = require('gulp-util');
var gulpif = require('gulp-if');
var streamify = require('gulp-streamify');
var autoprefixer = require('gulp-autoprefixer');
var cssmin = require('gulp-cssmin');
var less = require('gulp-less');
var concat = require('gulp-concat');
var plumber = require('gulp-plumber');
var source = require('vinyl-source-stream');
var babelify = require('babelify');
var browserify = require('browserify');
var watchify = require('watchify');
var uglify = require('gulp-uglify');
var production = process.env.NODE_ENV === 'production';
var dependencies = [
'alt',
'react#39;,
'react-dom',
'react-router',
'underscore'
];
/*
|--------------------------------------------------------------------------
| Combine all JS libraries into a single file for fewer HTTP requests.
|--------------------------------------------------------------------------
*/
gulp.task('vendor', function() {
return gulp.src([
'bower_components/jquery/dist/jquery.js',
'bower_components/bootstrap/dist/js/bootstrap.js',
'bower_components/magnific-popup/dist/jquery.magnific-popup.js',
'bower_components/toastr/toastr.js'
]).pipe(concat('vendor.js'))
.pipe(gulpif(production, uglify({ mangle: false })))
.pipe(gulp.dest('public/js'));
});
/*
|--------------------------------------------------------------------------
| Compile third-party dependencies separately for faster performance.
|--------------------------------------------------------------------------
*/
gulp.task('browserify-vendor', function() {
return browserify()
.require(dependencies)
.bundle()
.pipe(source('vendor.bundle.js'))
.pipe(gulpif(production, streamify(uglify({ mangle: false }))))
.pipe(gulp.dest('public/js'));
});
/*
|--------------------------------------------------------------------------
| Compile only project files, excluding all third-party dependencies.
|--------------------------------------------------------------------------
*/
gulp.task('browserify', ['browserify-vendor'], function() {
return browserify('app/main.js')
.external(dependencies)
.transform(babelify, { presets: ['es2015', 'react'] })
.bundle()
.pipe(source('bundle.js'))
.pipe(gulpif(production, streamify(uglify({ mangle: false }))))
.pipe(gulp.dest('public/js'));
});
/*
|--------------------------------------------------------------------------
| Same as browserify task, but will also watch for changes and re-compile.
|--------------------------------------------------------------------------
*/
gulp.task('browserify-watch', ['browserify-vendor'], function() {
var bundler = watchify(browserify('app/main.js', watchify.args));
bundler.external(dependencies);
bundler.transform(babelify, { presets: ['es2015', 'react'] })
bundler.on('update', rebundle);
return rebundle();
function rebundle() {
var start = Date.now();
return bundler.bundle()
.on('error', function(err) {
gutil.log(gutil.colors.red(err.toString()));
})
.on('end', function() {
gutil.log(gutil.colors.green('Finished rebundling in', (Date.now() - start) + 'ms.'));
})
.pipe(source('bundle.js'))
.pipe(gulp.dest('public/js/'));
}
});
/*
|--------------------------------------------------------------------------
| Compile LESS stylesheets.
|--------------------------------------------------------------------------
*/
gulp.task('styles', function() {
return gulp.src('app/stylesheets/main.less')
.pipe(plumber())
.pipe(less())
.pipe(autoprefixer())
.pipe(gulpif(production, cssmin()))
.pipe(gulp.dest('public/css'));
});
gulp.task('watch', function() {
gulp.watch('app/stylesheets/**/*.less', ['styles']);
});
gulp.task('default', ['styles', 'vendor', 'browserify-watch', 'watch']);
gulp.task('build', ['styles', 'vendor', 'browserify']);
</code></pre>
<p><strong>November 12, 2015 Update:</strong> Updated <code>babelify</code> transform to use <a href="http://babeljs.io/docs/plugins/preset-es2015/"><strong>es2015</strong></a> and <a href="http://babeljs.io/docs/plugins/preset-react/"><strong>react</strong></a> presets.</p>
<p>Note</p>
<p>If you have not used Gulp before, this is a great starting point — <a href="http://www.sitepoint.com/introduction-gulp-js/">An Introduction to Gulp.js</a>. </p>
<p>Although the code should be more or less self-explanatory with those task names and code comments, let's briefly go over each task for completeness.</p>
<p>Gulp Task Description</p>
<p><code>vendor</code><br/>
Concatenates all JS libraries into one file.</p>
<p><code>browserify-vendor</code><br/>
For performance reasons, NPM modules specified in the <code>dependencies</code> array are compiled and bundled separately. As a result, <u>bundle.js</u> recompiles a few hundred milliseconds faster.</p>
<p><code>browserify</code><br/>
Compiles and bundles just the app files, without any external modules like <u>react</u> and <u>react-router</u>.</p>
<p><code>browserify-watch</code><br/>
Essentially the same task as above but it will also listen for changes and re-compile <u>bundle.js</u>.</p>
<p><code>styles</code><br/>
Compiles LESS stylesheets and automatically adds browser prefixes if necessary.</p>
<p><code>watch</code><br/>
Re-compiles LESS stylesheets on file changes.</p>
<p><code>default</code><br/>
Runs all of the above tasks and starts watching for file changes.</p>
<p><code>build</code><br/>
Runs all of the above tasks then exits.</p>
<p>Next, we will shift focus to the project structure by creating files and folders that <u>gulpfile.js</u> is expecting.</p>
<h2 id="toc_7">Step 3. Project Structure</h2>
<p>In the <strong>__public</strong> directory create 4 new folders <strong>__css</strong>, <strong>__js</strong>, <strong>__fonts</strong> and <strong>__img</strong>. Also, download this <a href="https://raw.githubusercontent.com/sahat/newedenfaces-react/master/public/favicon.png">favicon.png</a> and place it here as well.</p>
<p><img src="/images/blog/Screenshot%202015-06-21%2000.47.32.png" alt=""/></p>
<p>In the <strong>__newedenfaces</strong> directory (project root), create a new folder <strong>__app</strong>.</p>
<p>Then inside <strong>__app</strong> create 4 new folders <strong>__actions</strong>, <strong>__components</strong>, <strong>__stores</strong>, <strong>__stylesheets</strong> and 3 empty files <u>alt.js</u>, <u>routes.js</u> and <u>main.js</u>.</p>
<p><img src="/images/blog/Screenshot%202015-06-21%2000.58.43.png" alt=""/></p>
<p>In the <strong>__stylesheets</strong> directory create a new file <u>main.less</u> which we will populate with CSS styles shortly.</p>
<p>Back in the project root directory (<strong>__newedenfaces</strong>), create a new file <u>bower.json</u> and paste the following:</p>
<pre><code>{
"name": "newedenfaces",
"dependencies": {
"jquery": "^2.1.4",
"bootstrap": "^3.3.5",
"magnific-popup": "^1.0.0",
"toastr": "^2.1.1"
}
}
</code></pre>
<p>Note</p>
<p>Bower is a package manager that lets you easily download JavaScript libraries, such as the ones specified above, via a command line instead of visiting each individual website, downloading, extracting and adding it to the project manually. </p>
<p>Run <code>bower install</code> and wait for the packages to be downloaded and installed into the <strong>__bower_components</strong> directory. You can change that path using the <a href="http://bower.io/docs/config/#directory">_.bowerrc_</a> file, but for the purposes of this tutorial we will stick with the defaults.</p>
<p>Similarly to <strong>__node_modules</strong>, you should not commit <strong>__bower_components</strong> into a Git repository. But hold on, if we don't commit it to Git, how will those files be loaded when you deploy your app? We will revisit this issue later during the deployment step of this tutorial.</p>
<p>Copy all glyphicons fonts from <strong>__bower_components/bootstrap/fonts</strong> into <strong>__public/fonts</strong> directory.</p>
<p>Download and extract the following background images and place them into <strong>__public/img</strong> directory:</p>
<ul>
<li><a href="/assets/Background%20Images.zip">Background Images.zip</a></li>
</ul>
<p>Fun Fact</p>
<p>I have used the Gaussian blur in Adobe Photoshop in order to create that out of focus effect over 3 years ago when I built the original New Eden Faces project, but now it should be totally possible to achieve a similar effect using [CSS filters>. <div> </p>
<p>Open <u>main.less</u> that we just created and paste the following styles from the link below. Due to the sheer length of it, I have decided to include it as a separate file.</p>
<ul>
<li><a href="https://github.com/sahat/newedenfaces-react/blob/master/app/stylesheets/main.less">__ main.less</a></li>
</ul>
<p>If you have used the <a href="http://getbootstrap.com/">Bootstrap</a> CSS framework in the past, then most of it should be already familiar to you.</p>
<p>I don't know if you are aware of the latest <a href="https://speakerdeck.com/vjeux/react-css-in-js">trend</a> to include styles directly inside React components, but I am not sure if I like this new practice. Perhaps when tooling gets better I will revisit this topic, until then I will use external stylesheets like I always have been. However, if you are interested in using modular CSS, check out <a href="https://github.com/css-modules/css-modulesify">css-modulesify</a>.</p>
<p><strong>October 19, 2015 Update:</strong> If you are building reusable React components like <a href="http://elemental-ui.com/">Elemental UI</a> and <a href="http://material-ui.com/">Material UI</a> then by all means do it. Personally, I would actually prefer if I don't have to import accompanying "vendor" stylesheets, as we do with just much every user-interface jQuery library.</p>
<p>Before we jump into building the React app, I have decided to dedicate the next three sections to ES6, React, Flux, otherwise it may be too overwhelming trying to learn everything at once. Personally, I had a very hard time following some React + Flux code examples written in ES6 because I was learning a new syntax, a new framework and a completely unfamiliar app architecture all at once.</p>
<p>Since I cannot cover everything in-depth, we will be going over only those topics that you need to know for this tutorial.</p>
<h2 id="toc_8">Step 4. ES6 Crash Course</h2>
<p>The best way to learn ES6 is by showing an equivalent ES5 code for every ES6 example. Again, I will only be covering what you need to know for this tutorial. There are plenty of blog posts that go in great detail about the new ES6 features.</p>
<p><strong>__Modules (Import)</strong></p>
<pre><code>// ES6
import React from 'react';
import {Route, DefaultRoute, NotFoundRoute} from 'react-router';
// ES5
var React = require('react');
var Router = require('react-router');
var Route = Router.Route;
var DefaultRoute = Router.DefaultRoute;
var NotFoundRoute = Router.NotFoundRoute;
</code></pre>
<p>Using the ES6 <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">destructuring assignment</a> we can import a subset of a module which can be quite useful for modules like <u>react-router</u> and <u>underscore</u> where it exports more than one function.</p>
<p>One thing to keep in mind is that ES6 imports are hoisted. All dependent modules will be loaded before any of the module code is executed. In other words, you can't conditionally load a module like with CommonJS. That did throw me off a little when I tried to import a module inside an if-else condition.</p>
<p>For a detailed overview of the <code>import</code> statement see this <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">MDN page</a>.</p>
<p><strong>__Modules (Export)</strong></p>
<pre><code>// ES6
function Add(x) {
return x + x;
}
export default Add;
// ES5
function Add(x) {
return x + x;
}
module.exports = Add;
</code></pre>
<p>To learn more about ES6 modules, as well as different ways of importing and exporting functions from a module, check out <a href="http://www.2ality.com/2014/09/es6-modules-final.html">ECMAScript 6 modules</a> and <a href="http://www.sitepoint.com/understanding-es6-modules/">Understanding ES6 Modules</a>.</p>
<p><strong>__Classes</strong></p>
<p>ES6 classes are nothing more than a syntactic sugar over the existing prototype-based inheritance in JavaScript. As long as you remember that fact, the <code>class</code> keyword will not seem like a foreign concept to you.</p>
<pre><code>// ES6
class Box {
constructor(length, width) {
this.length = length;
this.width = width;
}
calculateArea() {
return this.length * this.width;
}
}
let box = new Box(2, 2);
box.calculateArea(); // 4
// ES5
function Box(length, width) {
this.length = length;
this.width = width;
}
Box.prototype.calculateArea = function() {
return this.length * this.width;
}
var box = new Box(2, 2);
box.calculateArea(); // 4
</code></pre>
<p>With ES6 classes you can now use <code>extends</code> to create a subclass from an existing class:</p>
<pre><code>// ES6
class MyComponent extends React.Component {
// Now MyComponent contains all React component methods
// such as componentDidMount(), render() and etc.
}
// ES5
var MyComponent = React.createClass({
// Now MyComponent contains all React component methods
// such as componentDidMount(), render() and etc.
})
</code></pre>
<p><strong>October 19, 2015 Update:</strong> Added the ES5 example using <code>React.createClass</code>.</p>
<p>For more information about ES6 classes visit <a href="http://www.2ality.com/2015/02/es6-classes-final.html">Classes in ECMAScript 6</a> blog post.</p>
<p><strong>__<code>var</code> vs <code>let</code></strong></p>
<p>The only difference between the two is that <code>var</code> is scoped to the nearest <u>function block</u> and <code>let</code> is scoped to the nearest <u>enclosing block</u> - which could be a <u>function</u>, a <u>for-loop</u> or an <u>if-statement block</u>.</p>
<p>Here is a good [example][73] showing the difference between <code>var</code> and <code>let</code>:</p>
<pre><code> [73]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
</code></pre>
<p>var a = 5;<br/>
var b = 10;</p>
<pre><code>if (a === 5) {
let a = 4; // The scope is inside the if-block
var b = 1; // The scope is inside the function
console.log(a); // 4
console.log(b); // 1
}
console.log(a); // 5
console.log(b); // 1
</code></pre>
<p>Basically, <code>let</code> is block scoped, <code>var</code> is function scoped.</p>
<p><strong>__Arrow Functions (Fat Arrow)</strong></p>
<p>An arrow function expression has a shorter syntax compared to function expressions and lexically binds the <code>this</code> value.</p>
<pre><code>// ES6
[1, 2, 3].map(n => n * 2); // [2, 4, 6]
// ES5
[1, 2, 3].map(function(n) { return n * 2; }); // [2, 4, 6]
</code></pre>
<p>Note</p>
<p>Parentheses around the single argument are optional, so it is up to you whether you want to enforce it or not. Some see it as a bad practice, others think it's fine. </p>
<p>Besides a shorter syntax, what else is it useful for?</p>
<p>Consider the following example, straight from this project before I converted it to ES6.</p>
<pre><code>$.ajax({ type: 'POST', url: '/api/characters', data: { name: name, gender: gender } })
.done(function(data) {
this.setState({ helpBlock: data.message });
}.bind(this))
.fail(function(jqXhr) {
this.setState({ helpBlock: jqXhr.responseJSON.message });
}.bind(this))
.always(function() {
this.setState({ name: '', gender: '' });
}.bind(this));
</code></pre>
<p>Every function expression above creates its own <code>this</code> scope. Without binding <code>this</code> we would not be able to call <code>this.setState</code> in the example above, because <code>this</code> would have been <u>undefined</u>.</p>
<p>Alternatively, we could have assigned <code>this</code> to a variable, e.g. <code>var self = this</code> and then used <code>self.setState</code> instead of <code>this.setState</code> inside the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">closures</a> to get around this classic JavaScript problem.</p>
<p>In any case, here is an equivalent ES6 code using fat arrow functions which preserve the original <code>this</code> value:</p>
<pre><code>$.ajax({ type: 'POST', url: '/api/characters', data: { name: name, gender: gender } })
.done((data) => {
this.setState({ helpBlock: data.message });
})
.fail((jqXhr) => {
this.setState({ helpBlock: jqXhr.responseJSON.message });
})
.always(() => {
this.setState({ name: '', gender: '' });
});
</code></pre>
<p>Next, let's talk about React, what makes it so special and why should we use it.</p>
<h2 id="toc_9">Step 5. React Crash Course</h2>
<p>__ React is a JavaScript library for building web user interfaces. You could say it competes against __ AngularJS, __ Ember.js, __ Backbone and __ Polymer despite being much smaller in scope. React is just the <strong>V</strong> in the <strong>MVC</strong> (Model-View-Controller) architecture.</p>
<p>So, what is so special about React?</p>
<p>React components are written in a very declarative style. Unlike the "old way" using jQuery and such, you don't interact with DOM directly. React manages all UI updates when the underlying data changes.</p>
<p>React is also very fast thanks to the Virtual DOM and diffing algorithm under the hood. When the data changes, React calculates the minimum number of DOM manipulations needed, then efficiently re-renders the component. For example, if there are 10,000 rendered items on a page and only 1 item changes, React will update just that DOM element, leaving 9,999 other items unchanged. That's why React can get away with re-rendering the entire components without being ridiculously wasteful and slow.</p>
<p>Other notable features of React include:</p>
<ul>
<li><strong>Composability</strong>, i.e. make bigger, more complex components out of smaller components.</li>
<li><strong>Relatively easy to pick up</strong> since there isn't that much to learn and it does not have a massive documentation like AngularJS and Ember.js.</li>
<li><strong>Server-side rendering</strong> allows us to easily build <a href="https://medium.com/@mjackson/universal-javascript-4761051b7ae9">Isomorphic JavaScript apps</a>.</li>
<li>The most <strong>helpful error and warning messages</strong> that I have seen in any JavaScript library.</li>
<li><strong>Components are self-contained</strong>; markup and behavior (<a href="http://blog.vjeux.com/2014/javascript/react-css-in-js-nationjs.html">and even styles</a>) live in the same place, making components very reusable.</li>
</ul>
<p><strong>October 19, 2015 Update:</strong> We will not be building a true Isomorphic JavaScript app. If you disable JavaScript your Browser, a page will be rendered just fine for the most part, but it will not render any characters because that requires more work by fetching data from the database and then passing it to the root React component that will need to pass the data down to its children components, which is outside the scope of this tutorial. </p>
<p>I really like this excerpt from the <a href="http://facebook.github.io/react/blog/2015/07/03/react-v0.14-beta-1.html">React v0.14 Beta 1 blog post</a> announcement that sums up nicely what React is all about:</p>
<blockquote>
<p>It's become clear that the beauty and essence of React has nothing to do with browsers or the DOM. We think the true foundations of React are simply ideas of components and elements: being able to describe what you want to render in a declarative way.</p>
</blockquote>
<hr/>
<p>Before going any further please watch this awesome video <a href="https://egghead.io/lessons/react-react-in-7-minutes">React in 7 Minutes</a> by John Lindquist.</p>
<p>And while you are there, I highly recommend getting the <strong>PRO</strong> subscription ($24.99/month) to unlock over 94 React and <a href="https://facebook.github.io/react-native/">React Native</a> video lessons. No, you will not become an expert just by watching these videos, but they are amazing at giving you short and straight to the point explanations on any particular topic. If you are on a budget, you can subscribe for 1 month, download all the videos, then cancel your subscription at the end of the month. Subscribing not only gives you access to React lessons, but also to <a href="https://egghead.io/technologies/typescript">TypeScript</a>, <a href="https://egghead.io/technologies/angular2">Angular 2</a>, <a href="https://egghead.io/technologies/d3">D3</a>, <a href="https://egghead.io/technologies/es6">ECMAScript 6</a>, <a href="https://egghead.io/technologies/node">Node.js</a> and more.</p>
<p><strong>__ Disclaimer:</strong> I am not affiliated with <u>Egghead.io</u> and I do not get any commissions for referrals. </p>
<p>While learning React, the biggest challenge for me was that it required a completely different thinking approach to building UIs. Which is why reading <a href="https://facebook.github.io/react/docs/thinking-in-react.html">Thinking in React</a> guide is absolutely a must for anyone who is starting out with React.</p>
<p>In similar fashion to the <u>Product Table</u> from <a href="https://facebook.github.io/react/docs/thinking-in-react.html">Thinking in React</a>, if we are to break apart the <u>New Eden Faces</u> UI into potential components, this is what it would look like:</p>
<p><img src="/images/blog/Screen%20Shot%202015-06-21%20at%2011.45.38%20PM%20copy.png" alt=""/></p>
<p>Note</p>
<p>Each component should try to adhere to the <u>single responsibility principle</u>. If you find yourself working on a component that does too many things, perhaps it's best to split it into sub-components. Having said that, I typically write monolithic components first, just to get it working, then refactor it by splitting it into smaller sub-components. </p>
<p>The top-level App component contains Navbar, Homepage and Footer components. Homepage component contains two Character components.</p>
<p>So, whenever you have a certain UI design in mind, start by breaking it apart from top-down and always be mindful of how your data propagates from parent to child, child to parent and between sibling components or you will quickly find yourself completely lost. It may be difficult initially, but it will become second nature to you after building a few React apps.</p>
<p>So, next time you decide to build a new app in React, before writing any code, do this hierarchy outline first. It will help you to visualize the relationships between multiple components and build them accordingly.</p>
<hr/>
<p>All components in React have a <code>render()</code> method. It always returns a <u>single child</u> element. Conversly, the following return statement is invalid because it contains 3 child elements:</p>
<pre><code>render() {
// Invalid JSX
return (
<li>Achura</li>
<li>Civire</li>
<li>Deteis</li>
);
}
</code></pre>
<p>The HTML markup above is actually called <a href="https://facebook.github.io/react/docs/jsx-in-depth.html">JSX</a>. As far syntax goes, it is just slightly different from HTML, for example <code>className</code> instead of <code>class</code> to define CSS classes. You will learn more about it as we start building the app.</p>
<p>When I first saw that syntax, I was immediately repulsed by it. I am used to returning booleans, numbers, strings, objects and functions in JavaScript, but certaintly not that. However, JSX is actually just a syntactic sugar. After fixing the code above by wrapping it with a <code><ul></code> tag (must return a single element), here is what it looks like without JSX:</p>
<pre><code>render() {
return React.createElement('ul', null,
React.createElement('li', null, 'Achura'),
React.createElement('li', null, 'Civire'),
React.createElement('li', null, 'Deteis')
);
}
</code></pre>
<p>I think you will agree that JSX is far more readable than plain JavaScript. Furthermore, <a href="http://babeljs.io/">Babel</a> has a built-in support for JSX, so we don't need to install anything extra. If you have ever worked with AngularJS directives then you will appreciate working with React components, so instead of having two different files — <u>directive.js</u> (logic) and <u>template.html</u> (presentation), you have a single file containing both logic and presentation.</p>
<p>The <a href="https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount"><code>componentDidMount</code></a> method in React is the closest thing to <a href="https://learn.jquery.com/using-jquery-core/document-ready/"><code>$(document).ready</code></a> in jQuery. This method runs once (<a href="https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount">only on the client</a>) immediately after initial rendering of the component. This is where you would typically initialize third-party libraries and jQuery plugins, or connect to Socket.IO.</p>
<p>You will be using <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Ternary operator</a> in the <a href="https://facebook.github.io/react/docs/component-specs.html#render"><code>render</code></a> method quite a lot: hiding an element when data is empty, conditionally using CSS classes depending on some value, hiding or showing certain elements based on the component's state and etc.</p>
<p>Consider the following example that conditionally sets the CSS class to text-danger or text-success based on the props value.</p>
<pre><code>render() {
let delta = this.props.delta ? (
<strong className={this.props.delta > 0 ? 'text-success' : 'text-danger'}>
{this.props.delta}
</strong>
) : null;
return (
<div className='card'>
{delta}
{this.props.title}
</div>
);
}
</code></pre>
<p>We have only scratched the surface of everything there is to React, but this should be enough to give you a general idea about React as well as its benefits.</p>
<p>React on its own is actually really simple and easy to grasp. However, it is when we start talking about <a href="https://facebook.github.io/flux/">Flux</a> architecture, things can get a little confusing.</p>
<h2 id="toc_10">Step 6. Flux Architecture Crash Course</h2>
<p>Flux is the application architecture that was developed at Facebook for building scalable client-side web applications. It complements React's components by utilizing a unidirectional data flow. Flux is more of a pattern than a framework, however, we will be using a Flux library called <a href="http://alt.js.org">Alt</a> to minimize writing the boilerplate code.</p>
<p>Have you seen this diagram before? Did it make any sense to you? It did not make any sense to me, no matter how many times I looked at it.</p>
<p><img src="/images/blog/flux-diagram.png" alt=""/></p>
<p>Now that I understand it better, I am actually really amazed by how such simple architecture can be presented in a such complicated way. But to Facebook's credit, their <a href="https://facebook.github.io/flux/docs/overview.html#structure-and-data-flow">new Flux diagrams</a> are much better than before.</p>
<p>Fun Fact</p>
<p>When I first began writing this tutorial I decided not to use Flux in this project. I could not grasp it for the life of me, let alone teach it to others. But thankfully, I get to work on cool stuff at Yahoo where I get to play and experiment with different technologies during my work hours. Honestly, we could have built this app without Flux and it would have been less lines of code. We don't have here any complex or nested components. But I believe that showing a full-stack React app with server-side rendering and Flux architecture, to see how all pieces connect together, has a value in of itself. </p>
<p>Instead of reiterating the <a href="https://facebook.github.io/flux/docs/overview.html">Flux Overview</a>, let's take a look at one of the real-world use cases in order to illustrate how Flux works:</p>
<p><img src="/images/blog/Screenshot%202015-06-22%2002.18.48.png" alt=""/></p>
<ol>
<li><p>On <code>componentDidLoad</code> (when the page is rendered) three actions are fired:</p>
<p>OverviewActions.getSummary();<br/>
OverviewActions.getApps();<br/>
OverviewActions.getCompanies();</p></li>
<li><p>Each one of those actions makes an AJAX request to the server to fetch the data.</p></li>
<li><p>When the data is fetched, each action fires another <u>"success"</u> action and passes the data along with it:</p>
<p>getSummary() {<br/>
request<br/>
.get('/api/overview/summary')<br/>
.end((err, res) => {<br/>
this.actions.getSummarySuccess(res.body);<br/>
});<br/>
}</p></li>
<li><p>Meanwhile, the <u>Overview</u> store (a place where we keep the state for <u>Overview</u> component) is listening for those <u>"success"</u> actions. When the <code>getSummarySuccess</code> action is fired, <code>onGetSummarySuccess</code> method in the <u>Overview</u> store is called and the store is updated:</p>
<p>class OverviewStore {</p>
<p>constructor() {<br/>
this.bindActions(OverviewActions);<br/>
this.summary = {};<br/>
this.apps = [];<br/>
this.companies = [];<br/>
}</p>
<p>onGetSummarySuccess(data) {<br/>
this.summary = data;<br/>
}</p>
<p>onGetAppsSuccess(data) {<br/>
this.apps = data;<br/>
}</p>
<p>onGetCompaniesSuccess(data) {<br/>
this.companies = data;<br/>
}<br/>
}</p></li>
<li><p>As soon as the store is updated, the <u>Overview</u> component will know about it because it has subscribed to the <u>Overview</u> store. When a store is updated/changed, a component will set its own state to whatever is in that store.</p>
<p>class Overview extends React.Component {</p>
<p>constructor(props) {<br/>
super(props);<br/>
this.state = OverviewStore.getState();<br/>
this.onChange = this.onChange.bind(this);<br/>
}</p>
<p>componentDidMount() {<br/>
OverviewStore.listen(this.onChange);<br/>
}</p>
<p>onChange() {<br/>
this.setState(OverviewStore.getState())<br/>
}</p>
<p>...<br/>
}</p></li>
<li><p>At this point the <u>Overview</u> component has been updated with the new data.</p></li>
<li><p>In screenshot above,when the date range is updated from the dropdown menu, the entire process is repeated all over again.</p></li>
</ol>
<p>Note</p>
<p>Action names do not matter, use whatever naming convention you want as long as it is descriptive and makes sense. </p>
<p>Ignoring the <u>Dispatcher</u> for a moment, can you see the one-way flow outlined above? If not, it's alright, it will start making more sense as we start building the app.</p>
<p><img src="/images/blog/flux-simple-f8-diagram-1300w.png" alt=""/></p>
<p><strong>Flux Summary</strong></p>
<p>Flux is really just a fancy term for <strong>pub/sub</strong> architecture, i.e. data always flows one way through the application and it is picked up along the way by various subscribers (stores) who are listening to it.</p>
<hr/>
<p>There are more than a dozen of Flux implementations at the time of this writing. Out of them all, I only have experience with <a href="https://github.com/spoike/refluxjs">RefluxJS</a> and <a href="http://alt.js.org/">Alt</a>. Between the two, I personally prefer Alt for its simplicity, great support by <a href="https://github.com/goatslacker">_@goatslacker_</a>, server-side rendering support, great documentation and the project is actively maintained.</p>
<p>I strongly encourage you to go through the Alt's <a href="http://alt.js.org/guide/">Getting Started</a> guide. It will take no more than 10 minutes to skim through it.</p>
<p>If you are undecided on the Flux library, consider the following <a href="https://news.ycombinator.com/item?id=9833099">comment</a> by <u>glenjamin</u> on Hacker News, in response to having a hard time figuring out which Flux library to use:</p>