├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── egghead.io_video_tutorial_notes.md
├── index.html
├── package.json
└── static-server.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (https://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | _**Please read** our_
2 | [**contribution guide**](https://github.com/dwyl/contributing)
3 | (_thank you_!)
4 |
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
87 |
88 | #### tl;dr
89 |
90 | Read more about JavaScript's Reduce (Array method):
91 | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
92 | and how to reduce an array of Objects:
93 | https://stackoverflow.com/questions/5732043/javascript-reduce-on-array-of-objects
94 | understanding these two things will help you grasp why Redux is so simple.
95 |
96 | You will see this abbreviated/codified as `(state, action) => state`
97 | to understand what this means, watch: [youtu.be/xsSnOQynTHs?t=15m51s](https://youtu.be/xsSnOQynTHs?t=15m51s)
98 |
99 |
100 | ## How?
101 |
102 | ### Learn Where Redux Got It's _Best_ Ideas From!
103 |
104 | [Redux](https://github.com/dwyl/learn-redux) "_takes cues from_"
105 | (_i.e. takes **all** it's **best ideas/features** from_) Elm.
106 | 
107 | So... by learning **The Elm _Architecture_**,
108 | you will **_intrinsically_ understand Redux**
109 | which will help you learn/develop React apps.
110 |
111 | We wrote a ***complete beginner's step-by-step introduction***
112 | to **The Elm _Architecture_** for **JavaScript** developers:
113 | [github.com/dwyl/**learn-elm-architecture**-in-**javascript**](https://github.com/dwyl/learn-elm-architecture-in-javascript)
114 |
115 | If _after_ you've learned Redux and built a couple of React Apps,
116 | you decide you want to discover where all the _best_ ideas
117 | in the React _ecosystem_ came from,
118 | checkout: [github.com/dwyl/**learn-elm**](https://github.com/dwyl/learn-elm)
119 |
120 |
121 |
122 | ### Learn from the _Creator_ of Redux!
123 |
124 | The *fastest* way to learn Redux is to watch the
125 | [Introductory Video Tutorials](https://egghead.io/series/getting-started-with-redux)
126 | recoded by **Dan Abramov** (*the Creator of Redux*).
127 | The videos are broken down into "bite size" chunks which are easily digestible.
128 | Total viewing time for the videos is [**66 minutes**]()
129 |
130 | We have made a set of ***comprehensive notes/transcriptions*** on the videos, these are in:
131 | [egghead.io_**video_tutorial**_***notes***.md](https://github.com/dwyl/learn-redux/blob/master/egghead.io_video_tutorial_notes.md)
132 |
133 | We _recommend_ keeping the **notes** open in a distinct window/browser
134 | while you are watching the videos; you can go a *lot* faster because all the sample code is included
135 | and if for any reason you do not _understand_ what Dan is saying you have the notes to refer to.
136 |
137 | 
138 |
139 | > *Please* give feedback and suggest improvements by creating issues on GitHub:
140 | https://github.com/dwyl/learn-redux/issues
141 | *Thanks*!
142 |
143 |
144 |
145 |
146 | ## Background Reading / Watching / Listening
147 |
148 | + GitHub Project: https://github.com/reduxjs/redux
149 | + Online Documentation: https://redux.js.org/
150 | + ***Interview*** with [@gaearon](https://github.com/gaearon) (*Dan Abramov - creator of Redux*)
151 | on The **Changelog** Podcast: https://changelog.com/187 -
152 | Good history and insight into his motivations for learning to program
153 | and the journey that lead him to writing Redux.
154 | + Smart and Dumb Components by [Dan Abramov](https://github.com/gaearon)
155 | https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
156 | + Redux: Simplifying Application State in JavaScript -
157 | https://youtu.be/okdC5gcD-dM (*good overview by* [**Tim Griesser**](https://github.com/tgriesser) December 2015)
158 | + [Write Yourself A Redux](https://zapier.com/engineering/how-to-build-redux/) by Justin Deal/Zapier Engineering - Goes over the entire architecture and lets you build your own Redux _from scratch_! (April 27, 2017)
159 | + ***Ducks*** - a proposal for bundling reducers, action types and actions when using Redux - by [Erik Rasmussen](https://github.com/erikras)
160 | https://github.com/erikras/ducks-modular-redux
161 | + Redux ***best practices*** by [Will Becker](https://github.com/wbecker) https://medium.com/lexical-labs-engineering/redux-best-practices-64d59775802e
162 | + Starter boilerplate for a universal webapp using express, react, redux, webpack, and react-transform: https://github.com/erikras/react-redux-universal-hot-example
163 | + Full-Stack Redux Tutorial (Redux, React & Immutable.js) by
164 | [@teropa](https://github.com/teropa)
165 | https://teropa.info/blog/2015/09/10/full-stack-redux-tutorial.html - really good but takes 4h+!
166 | + Single source of truth: https://en.wikipedia.org/wiki/Single_Source_of_Truth
167 | + Redux Undo: https://github.com/omnidan/redux-undo
168 | + **Cartoon!** On Redux: https://code-cartoons.com/a-cartoon-intro-to-redux-3afb775501a6#.f9fhidgvl
169 | + ...And flux: https://code-cartoons.com/a-cartoon-guide-to-flux-6157355ab207#.jdauhkpjg
170 | + ...And time travel debugging (this one's short)! https://code-cartoons.com/hot-reloading-and-time-travel-debugging-what-are-they-3c8ed2812f35#.cvkq7d5du
171 |
172 | ### Architecture
173 |
174 | If you are building a React-based app
175 | you will most likely be using [react-router](https://github.com/rackt/react-router)
176 | to manage the routing of your client-side app ...
177 | React-Router manages an important piece of your application state:
178 | the URL. If you are using redux, you want your app state to fully
179 | represent your UI; if you snapshotted the app state,
180 | you should be able to load it up later and see the same thing.
181 |
182 | + Keep react-router and redux in sync: https://github.com/rackt/redux-simple-router
183 | + A Simple Way to Route with Redux (November 25, 2015) by [James Long @Mozilla](https://github.com/jlongster)
184 | https://jlongster.com/A-Simple-Way-to-Route-with-Redux
185 |
186 | ### Size (*Matters*)
187 |
188 | At the time of writing, the *minified* version of Redux is
189 | [**5.4kb**](https://github.com/dwyl/learn-redux/issues/11#issue-124671091)
190 | which is even *smaller* when GZipped!
191 |
192 |
193 | ## Frequently Asked Questions (*FAQ*)
194 |
195 | ### (Do I *Need* to use) React ?
196 |
197 | **Short Answer**: ***No***, Redux does not depend on or require you to use React; the two are separate and can be learned/used independently.
198 |
199 | **Longer Answer**:
200 | While *many* Redux apps and tutorials use React, Redux is ***totally separate*** from React. Dan's EggHead Video Tutorials do feature React heavily from **Lesson 8** *onwards*.
201 |
202 | React is a *good* fit for rendering views in a Redux-based app, however there are many other *great* alternative component-based virtual-DOM-enabled view rendering libraries (*#mouth-full*) that work *really* well with Redux; e.g: https://github.com/anthonyshort/deku
203 |
204 | Considering that React is *the* fastest growing "*view*" (*DOM Rendering*) library of 2015
205 | and the pace of its' adoption looks set to *continue* in 2016
206 | ... so it won't *hurt* you to know *how* to use React.
207 |
208 | We've made some notes to help you get started learning React:
209 | https://github.com/dwyl/learn-react
210 |
211 | You can/should use Redux to *organise* your application and ***optionally*** use React
212 | to `render` your views.
213 |
214 | ### (*Should I use*) Immutable.js ?
215 |
216 | **Short Answer**: ***Not Yet!***
217 |
218 | **Longer Answer**:
219 | The *convention* in Redux apps is for the `state` to be
220 | [`immutable`](https://stackoverflow.com/questions/3200211/what-does-immutable-mean)
221 | this makes your app far more predictable because
222 | any/all changes to the `state` have to be done via an `action`.
223 |
224 | [Immutable.js](https://facebook.github.io/immutable-js/)
225 | makes the data structures in your application `state`
226 | more efficient (*in larger apps*) however,
227 | while you are learning Redux we suggest you ignore **immutable.js**
228 | as you will have more than enough to master for now.
229 |
230 | Once you have published your first app using Redux,
231 | come back to immutable.js to appreciate how it makes ***large apps***
232 | run faster. As Lee Byron, the *creator* of Immutable.js states,
233 | for small apps without much change in `state`, adding Immutable.js
234 | will actually make your app perform *worse*!
235 |
236 | If you want to understand *why* using Immutable.js
237 | can be a ***good*** thing in ***large apps***, watch
238 | [Lee Byron's intro to Immutable](https://www.youtube.com/watch?v=kbnUIhsX2ds)
239 |
240 |
241 | ## Todo: [](https://github.com/dwyl/learn-redux/issues)
242 |
243 | + [ ] Explain why ***Unidirectional Data Flow*** is this "better" than bi-directional e.g: Angular.js
244 |
245 | ## Kudos to Fellow *DWYLers*
246 |
247 | > Props to [***Rafe***](https://github.com/rjmk) for telling us about Redux and Elm: https://github.com/rjmk/reducks *before* it was *cool*
248 | > Thanks to [***Milo***](https://github.com/bananaoomarang) for his
249 | *fantastic* demo/example: https://github.com/bananaoomarang/isomorphic-redux
250 | (*which he has painstakingly kept up-to-date with the latest Redux/React versions!*)
251 | > and *love* to [***Niki***](https://github.com/nikhilaravi) &
252 | > [***Jack***](https://github.com/jrans) for their
253 | > *enthusiasm* and *patience* while explaining it all to us ...
254 |
255 | ## *Thanks* for Learning with Us!
256 |
257 | If you found our notes useful, please share them with others by
258 | starring this repo and/or re-tweeting:
259 |
260 | [](https://twitter.com/dwylhq/status/687703493264732160)
261 |
262 | > https://twitter.com/dwylhq/status/687703493264732160
263 |
--------------------------------------------------------------------------------
/egghead.io_video_tutorial_notes.md:
--------------------------------------------------------------------------------
1 |
2 | ## Notes for Dan Abramov's egghead.io Videos [](https://github.com/nelsonic/learn-redux/issues)
3 |
4 | #### 1. The Single Immutable State Tree (*Principal #1*)
5 |
6 | > Video: https://egghead.io/lessons/javascript-redux-the-single-immutable-state-tree
7 |
8 | The **first principal** to learn in Redux is that you are going to represent your whole
9 | application ("State") as a single JavaScript Object. All changes and mutations
10 | to the state in Redux are *explicit* so it is possible to keep track of all of them.
11 |
12 | In this video Dan shows how the state of a Todo app changes over time as
13 | data is added and filters applied; its a *glimpse* of power of the single state tree.
14 |
15 |
16 |
17 | #### 2. Describing State Changes with Actions (*Principal #2*)
18 |
19 | > Video: https://egghead.io/lessons/javascript-redux-describing-state-changes-with-actions
20 |
21 | The **second principal** of Redux is that the **state tree** is ***read-only***;
22 | you cannot modify or write to it, instead, any time you want to change the state
23 | you need to dispatch an action. (i.e. *you can only "update" the state using a function*...)
24 | An action is a *plain Javascript Object* describing the change.
25 | Just like the state is the minimal representation of data in your app,
26 | the action is the minimal representation of the change to that data.
27 | The only requirement of an action is that it has a `type` property
28 | (*this more a description for your action*). The convention is to use a `String`
29 | because they are serializable (*i.e. easy to `JSON.stringify`*)
30 |
31 | > "*Any data that gets into your Redux Application gets there by actions*"
32 |
33 |
34 |
35 | #### 3. *Pure* and *Impure* Functions
36 |
37 | > Video: https://egghead.io/lessons/javascript-redux-pure-and-impure-functions
38 |
39 | Pure functions depend solely on the values of the arguments.
40 | Pure functions do not have any (*observable*) side-effects such as network
41 | or database calls. Pure functions just calculate the new value [of the state].
42 |
43 | The functions you write in redux need to be pure.
44 |
45 | #### 4. The Reducer Function (*Principal #3*)
46 |
47 | > Video: https://egghead.io/lessons/javascript-redux-the-reducer-function
48 |
49 | The UI/View layer of an application is most predictable when it is described
50 | as a pure function of the application state. Pioneered by ~~React~~ [Ractive](https://github.com/ractivejs/ractive) and now adopted by several other
51 | frameworks, Redux compliments this approach with another idea:
52 | the state mutations in your app need to be described as a pure function
53 | that takes the previous state and the action being "dispatched" (*performed*)
54 | and returns the next state of your app.
55 |
56 | Inside any Redux app there is one function that takes the state of the whole
57 | application and the action being dispatched and returns the next state of
58 | the whole application. It is important that it does not modify the state given
59 | to it; it has to be pure, so it has to `return` a new `Object`
60 | Even in *large* applications there is still just a simple function
61 | that manages how the next state is calculated based on the previous state
62 | of the whole application and the action being dispatched.
63 | It does not have to be slow, for example: if I change the visibility filter
64 | I have to create the new object for the whole state, but I can keep the
65 | reference to the previous version of the Todo's array because the list of
66 | todos has not changed when we change the visibility filter; this is what makes
67 | Redux fast.
68 |
69 | > this is the 3rd and final principal of Redux: to describe state changes
70 | you have to write a function that takes the previous state of the app
71 | and the action being dispatched and returns the next state.
72 | The function has to be pure and is called the "Reducer".
73 |
74 |
75 |
76 | #### 5. Writing a Counter Reducer with Tests
77 |
78 | This video walks through creating a basic counter in Redux.
79 |
80 | > Video: https://egghead.io/lessons/javascript-redux-writing-a-counter-reducer-with-tests
81 |
82 | The first [*and only*] function in this video is the Reducer for the counter example.
83 | A reducer accepts state and action as arguments and returns the next state.
84 |
85 | Before writing any code, we write a few assertions (*tests*) using
86 | [**Michael Jackson**](https://github.com/mjackson)'s
87 | (*Yes, there's a* ***developer*** *with that name... and he's* ***really good***)
88 | ***Expect*** (testing/assertion) **library**: https://github.com/mjackson/expect
89 |
90 | We assert that when the state of the counter is zero and you pass an `INCREMENT`
91 | action, it should return 1.
92 |
93 | ```js
94 | expect (
95 | counter(0, { type: 'INCREMENT' })
96 | ).toEqual(1);
97 | ```
98 |
99 | And similarly when the counter is 1 and we `INCREMENT` it should return 2.
100 |
101 | ```js
102 | expect (
103 | counter(1, { type: 'INCREMENT' })
104 | ).toEqual(2);
105 |
106 | // We add a test that check how `DECREMENT` works; from 2 to 1 and from 1 to zero:
107 |
108 | expect (
109 | counter(2, { type: 'DECREMENT' })
110 | ).toEqual(1);
111 |
112 | expect (
113 | counter(1, { type: 'DECREMENT' })
114 | ).toEqual(0);
115 | ```
116 |
117 | If we run these tests [*in the browser*], they will fail because we have not
118 | even *begun* to implement the reducer.
119 | We are going to start by checking the action type.
120 | If the action type is `INCREMENT` we are going to `return state + 1` (*state plus one*)
121 | If the type is `DECREMENT` we are going to `return state - 1` (*state minus one*)
122 |
123 | ```js
124 | if (action.type === 'INCREMENT') {
125 | return state + 1;
126 | } else if (action.type === 'DECREMENT') {
127 | return state - 1;
128 | }
129 | ```
130 |
131 | If you run the tests, you will find that that this is enough to get them to pass.
132 | > *Code for*
133 | [***Video 5 @ 1:15*** ](https://github.com/nelsonic/learn-redux/blob/8ded8853d5a789f94aff410eef0799bb66926a0d/index.html#L15)
134 |
135 | However, there are still some flaws in our implementation of the counter reducer.
136 | If we dispatch an action that it [*the reducer*] does not understand,
137 | it should return the current state of the application.
138 |
139 | ```js
140 | expect (
141 | counter(1, { type: 'SOMETHING_ELSE' })
142 | ).toEqual(1);
143 | ```
144 |
145 | However if we check for that, we will see that this test fails
146 | because we currently don't handle unknown actions.
147 | So I'm going to add an `else` clause that returns the current state
148 | and the tests pass now.
149 |
150 | ```js
151 | if (action.type === 'INCREMENT') {
152 | return state + 1;
153 | } else if (action.type === 'DECREMENT') {
154 | return state - 1;
155 | } else {
156 | return state;
157 | }
158 | ```
159 |
160 | And the tests pass now.
161 |
162 | > *Code for*
163 | [***Video 5 @ 1:49*** ](https://github.com/nelsonic/learn-redux/blob/d6c9051922e288583d5f43c45dbf3a57f1113648/index.html#L15)
164 |
165 | Another issue is that while the reducer is in control of the application state,
166 | *currently* it does not specify the initial state; in the case of the counter
167 | example that would be zero.
168 |
169 | The convention in Redux is that if the reducer receives `undefined` as the
170 | `state` argument, it *must* `return` what it considers to be the initial
171 | `state` of the application. In this case it will be zero.
172 |
173 | > *Code for*
174 | [***Video 5 @ 2:15*** ](https://github.com/nelsonic/learn-redux/blob/36775c88bb9d236f4918b1721c4d72c3ac8820a1/index.html#L18)
175 |
176 | "*Now come a few* ***cosmetic tweaks***" ... At the end of the video Dan replaces
177 | the `if/else` blocks with a `switch` statement* - which we *agree* is *neater* (*and works in* ***all browsers***)
178 |
179 | ```js
180 | switch (action.type) {
181 | case 'INCREMENT':
182 | return state + 1;
183 | case 'DECREMENT':
184 | return state - 1;
185 | default:
186 | return state;
187 | }
188 | ```
189 |
190 | *However* Dan *also* makes a couple of changes which are *not* just "*cosmetic*":
191 | changing the reducer function to be an **ES6**
192 | [`Arrow Function`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) and also includes an **ES6** [`default parameter`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/default_parameters)
193 | syntax to specify what the state should be if its undefined.
194 |
195 | The reducer function written in ES5 (*Works in* ***ALL Browsers***):
196 | ```js
197 | function counter(state, action) {
198 | state = state || 0; // default parameter assignment before ES6
199 | /* reducer code here */
200 | }
201 | ```
202 | is re-written using ES6 features: (***Only Chrome*** *fully-supports both these new features*)
203 |
204 | ```js
205 | const counter = (state = 0, action) => {
206 | /* reducer code here */
207 | }
208 | ```
209 |
210 | ***Arrow functions*** can be fewer characters to type but are
211 | [***not supported***](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Browser_compatibility)
212 | in **Safari** *or* **Internet Explorer**
213 | [*at the time of writing*] ...
214 | 
215 |
216 | ***Default parameters*** are a *nice* addition to JavaScript (ECMAScript 2015) because
217 | they make it clear what the default value of the parameter should be if its unset,
218 | however they are
219 | [***not supported***](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/default_parameters#Browser_compatibility) in **Internet Explorer**, **Safari** *or* **Opera** [*at the time of writing*] ...
220 | 
221 |
222 | These browsers still account for between 30%-50% of people using the internet in December 2015
223 | (*depending on the age/geography of the people using your app...
224 | see*: https://en.wikipedia.org/wiki/Usage_share_of_web_browsers )
225 | And considering that *most* people take *ages* to upgrade to the latest browser
226 | Microsoft ***Internet Explorer 8*** *still has*
227 | [***10%*** *market share*!](https://www.netmarketshare.com/browser-market-share.aspx?qprid=2&qpcustomd=0)
228 | and is [still available](https://www.microsoft.com/en-us/download/internet-explorer-8-details.aspx)
229 | to be downloaded.
230 |
231 | using ES6 features has two implications:
232 | + If you want to run the code in a browser you need Google Chrome ***Canary***.
233 | + And/Or, You need to "*transpile*" (*convert*) your code using ***Babel*** before running it in browsers.
234 |
235 | We will come back to Babel later...
236 |
237 |
238 |
239 |
240 | #### 6. Store Methods: getState(), dispatch(), and subscribe()
241 |
242 | > Video: https://egghead.io/lessons/javascript-redux-store-methods-getstate-dispatch-and-subscribe
243 | > Code: [Video 6 Code Snapshot]( https://github.com/nelsonic/learn-redux/blob/2430c6e95eacd61ebf7ff4a660cc64e80c9e883e/index.html)
244 |
245 | Video #6 picks up from where #5 finished, so if you skipped
246 | video 5, go back and watch it, and try writing/running the code!
247 |
248 | Dan starts off by showing how to include Redux (*from CDN JS*)
249 | in a client-side app so we can start using the methods.
250 | This is not the *recommended* way of loading Redux, but works fine for this
251 | example/demo.
252 |
253 | "*In real applications I suggest you use npm and a module bundler like
254 | webpack or browserify*".
255 |
256 |
257 | In this tutorial we are using a single function from Redux called `createStore`.
258 |
259 | Using **ES6** [**destructuring assignment**](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment)
260 | syntax to extract the `createStore` method from Redux:
261 |
262 | ```js
263 | const { createStore } = Redux; // 6 fewer characters to type. OMG! what will we do with all that extra free time?!
264 | // this is equivalent to:
265 | var createStore = Redux.createStore;
266 | ```
267 |
268 | "The store binds together the **3 Principals** of Redux,
269 | it holds the current application state object, it lets you dispatch actions.
270 | When you create it [the store] you need to specify the reducer that tells
271 | how to update the state with actions.
272 | In this example we are calling `createStore` with `counter` as the reducer
273 | that manages the state updates."
274 |
275 | Redux Store has **3** (*important*) **methods**:
276 |
277 | + `getState` - retrieves the current state of the Redux store. In the case of our counter the initial state is Zero.
278 | + `dispatch` - lets you dispatch actions to change the state of your application.
279 | if we log the state of the application after dispatching an action (e.g: `INCREMENT`), we see that the state has changed to 1.
280 | (*the most commonly used method*)
281 | + `subscribe` - lets you register a callback that the Redux store will call
282 | any time an action has been dispatched. so you can update the UI of your application to reflect the current application state.
283 |
284 | The code at the end of video #6 looks like this: (*explanatory comments added*)
285 |
286 | ```js
287 |
288 |