Skip to content

Commit fdcad0a

Browse files
committed
tutorial outline
1 parent 36d97fc commit fdcad0a

37 files changed

+365
-3
lines changed

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,38 @@ The data transformation
7373

7474
```js
7575
const reducer = (state) => {
76-
console.log('state: ', state);
76+
console.log(state);
7777
return state;
7878
};
7979
```
80+
81+
##### Combine Reducers
82+
83+
Using thunks for async actions.
84+
85+
##### Middleware
86+
87+
Using thunks for async actions.
88+
89+
##### Second Action
90+
91+
Creating a "SORT_BY_POPULARITY" action.
92+
93+
```js
94+
function sortByVotes(a, b) {
95+
switch(true) {
96+
case a.votes < b.votes:
97+
return 1;
98+
case a.votes > b.votes:
99+
return -1;
100+
default:
101+
return 0;
102+
}
103+
}
104+
```
105+
106+
Sort pokemon by votes
107+
108+
##### Thunk
109+
110+
Using thunks for async actions.

coderoad.json

Lines changed: 193 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
},
132132
{
133133
"title": "Reducer",
134-
"description": "The data transformation\n\n```js\nconst reducer = (state) => {\n console.log('state: ', state);\n return state;\n};\n```",
134+
"description": "The data transformation\n\n```js\nconst reducer = (state) => {\n console.log(state);\n return state;\n};\n```",
135135
"tasks": [
136136
{
137137
"description": "Create a reducer and call it as the first param in your `createStore`",
@@ -141,6 +141,198 @@
141141
"actions": [
142142
"open('index.js')"
143143
]
144+
},
145+
{
146+
"description": "Change the state",
147+
"tests": [
148+
"04/02"
149+
]
150+
},
151+
{
152+
"description": "Pass an action to the reducer",
153+
"tests": [
154+
"04/03"
155+
]
156+
},
157+
{
158+
"description": "Dispatch two voteUp actions through the reducer: `store.dispatch(voteUp(2))`",
159+
"tests": [
160+
"04/04"
161+
]
162+
},
163+
{
164+
"description": "Create a `switch` statement and pass in `action.type`, the default return should return `state`",
165+
"tests": [
166+
"04/05"
167+
]
168+
},
169+
{
170+
"description": "add a switch case for `VOTE_UP`. Inside of it, console.log the `id` of the action passed in\n\n# Pure Functions\n\n05/01\n```js\nconst nextPokemon = state.pokemon.map(p => {\n if (id === p.id) {\n p.votes += 1;\n }\n return p;\n });\n return {\n pokemon: nextPokemon\n };\n ```",
171+
"tests": [
172+
"04/06"
173+
]
174+
},
175+
{
176+
"description": "Return a new list of Pokemon with the pokemon matching the id incrementing its votes by one",
177+
"tests": [
178+
"05/01"
179+
]
180+
},
181+
{
182+
"description": "Use Object.assign",
183+
"tests": [
184+
"05/02"
185+
],
186+
"hints": [
187+
"return `Object.assign({}, { pokemon: nextPokemon });`"
188+
]
189+
}
190+
],
191+
"onPageComplete": ""
192+
},
193+
{
194+
"title": "Combine Reducers",
195+
"description": "Using thunks for async actions.",
196+
"tasks": [
197+
{
198+
"description": "import `combineReducers` from redux",
199+
"tests": [
200+
"06/01"
201+
]
202+
},
203+
{
204+
"description": "set reducers using combineReducers, pass it into store",
205+
"tests": [
206+
"06/02"
207+
]
208+
},
209+
{
210+
"description": "create a \"defaultPokemon\" state",
211+
"tests": [
212+
"06/03"
213+
]
214+
},
215+
{
216+
"description": "pass the default state into the pokemon reducer",
217+
"tests": [
218+
"06/04"
219+
]
220+
},
221+
{
222+
"description": "set the initial state to an empty object",
223+
"tests": [
224+
"06/05"
225+
]
226+
}
227+
]
228+
},
229+
{
230+
"title": "Middleware",
231+
"description": "Using thunks for async actions.",
232+
"tasks": [
233+
{
234+
"description": "import `applyMiddleware`",
235+
"tests": [
236+
"07/01"
237+
]
238+
},
239+
{
240+
"description": "set the second param in createStore to `applyMiddleware()`",
241+
"tests": [
242+
"07/02"
243+
]
244+
},
245+
{
246+
"description": "install \"redux-logger\" using npm",
247+
"tests": [
248+
"07/03"
249+
]
250+
},
251+
{
252+
"description": "create a \"logger\" as the result of `createLogger()`",
253+
"tests": [
254+
"07/04"
255+
]
256+
},
257+
{
258+
"description": "pass \"logger\" into `applyMiddleware()`",
259+
"tests": [
260+
"07/05"
261+
]
262+
}
263+
],
264+
"onPageComplete": "Look in the console"
265+
},
266+
{
267+
"title": "Second Action",
268+
"description": "Creating a \"SORT_BY_POPULARITY\" action.\n\n```js\nfunction sortByVotes(a, b) {\n switch(true) {\n case a.votes < b.votes:\n return 1;\n case a.votes > b.votes:\n return -1;\n default:\n return 0;\n }\n }\n```\n\nSort pokemon by votes",
269+
"tasks": [
270+
{
271+
"description": "create an action type for 'SORT_BY_POPULARITY'",
272+
"tests": [
273+
"08/01"
274+
]
275+
},
276+
{
277+
"description": "create an action creator called 'sortByPopularity'",
278+
"tests": [
279+
"08/02"
280+
]
281+
},
282+
{
283+
"description": "dispatch a `sortByPopularity` action after the two voteUp dispatches",
284+
"tests": [
285+
"08/03"
286+
]
287+
},
288+
{
289+
"description": "add a `SORT_BY_POPULARITY` case that returns `pokemon.sort();`",
290+
"tests": [
291+
"08/04"
292+
]
293+
},
294+
{
295+
"description": "create a sortByVotes function and pass it into the pokemon.sort function",
296+
"tests": [
297+
"08/05"
298+
]
299+
},
300+
{
301+
"description": "Make a `sortByKey` function, which is more reusable, by wrapping it in a function that takes a key",
302+
"tests": [
303+
"08/06"
304+
]
305+
},
306+
{
307+
"description": "You've just created a **thunk** - a function that returns a function. Pass your function into the pokemon.sort() method and give it the key of 'votes'",
308+
"tests": [
309+
"08/07"
310+
]
311+
}
312+
],
313+
"onPageComplete": "In the next step, we'll look at using thunks to call async actions"
314+
},
315+
{
316+
"title": "Thunk",
317+
"description": "Using thunks for async actions.",
318+
"tasks": [
319+
{
320+
"description": "install \"redux-thunk\" as a dependency",
321+
"tests": [
322+
"09/01"
323+
]
324+
},
325+
{
326+
"description": "import thunk from \"redux-thunk\"",
327+
"tests": [
328+
"09/02"
329+
]
330+
},
331+
{
332+
"description": "add thunk to applyMiddleware. The logger should always go last",
333+
"tests": [
334+
"09/03"
335+
]
144336
}
145337
]
146338
}

tutorial/04/01.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,12 @@ var spy = chai.spy.on(console, 'log');
88
/// load('index.js')
99

1010
describe('01 reducer', () => {
11+
it('doesn\'t take a "state" param', () => {
12+
expect(reducer).to.have.length(1);
13+
});
1114

15+
it('doesn\'t return "state"', () => {
16+
expect(reducer({ a: 1 }).to.deep.equal({ a: 1 });
17+
});
18+
1219
});

tutorial/04/03.js

Whitespace-only changes.

tutorial/04/04.js

Whitespace-only changes.

tutorial/04/05.js

Whitespace-only changes.

tutorial/04/06.js

Whitespace-only changes.

tutorial/04/index.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,26 @@ The data transformation
33

44
```js
55
const reducer = (state) => {
6-
console.log('state: ', state);
6+
console.log(state);
77
return state;
88
};
99
```
1010

1111
+ Create a reducer and call it as the first param in your `createStore`
1212
@test('04/01')
1313
@action(open('index.js'))
14+
15+
+ Change the state
16+
@test('04/02')
17+
18+
+ Pass an action to the reducer
19+
@test('04/03')
20+
21+
+ Dispatch two voteUp actions through the reducer: `store.dispatch(voteUp(2))`
22+
@test('04/04')
23+
24+
+ Create a `switch` statement and pass in `action.type`, the default return should return `state`
25+
@test('04/05')
26+
27+
+ add a switch case for `VOTE_UP`. Inside of it, console.log the `id` of the action passed in
28+
@test('04/06')

tutorial/05/01.js

Whitespace-only changes.

tutorial/05/02.js

Whitespace-only changes.

tutorial/05/index.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Pure Functions
2+
3+
05/01
4+
```js
5+
const nextPokemon = state.pokemon.map(p => {
6+
if (id === p.id) {
7+
p.votes += 1;
8+
}
9+
return p;
10+
});
11+
return {
12+
pokemon: nextPokemon
13+
};
14+
```
15+
16+
+ Return a new list of Pokemon with the pokemon matching the id incrementing its votes by one
17+
@test('05/01')
18+
19+
20+
21+
+ Use Object.assign
22+
@test('05/02')
23+
@hint('return `Object.assign({}, { pokemon: nextPokemon });`')
24+
25+
@onPageComplete('')

tutorial/06/01.js

Whitespace-only changes.

tutorial/06/02.js

Whitespace-only changes.

tutorial/06/03.js

Whitespace-only changes.

tutorial/06/04.js

Whitespace-only changes.

tutorial/06/05.js

Whitespace-only changes.

tutorial/06/index.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Combine Reducers
2+
Using thunks for async actions.
3+
4+
+ import `combineReducers` from redux
5+
@test('06/01')
6+
7+
+ set reducers using combineReducers, pass it into store
8+
@test('06/02')
9+
10+
+ create a "defaultPokemon" state
11+
@test('06/03')
12+
13+
+ pass the default state into the pokemon reducer
14+
@test('06/04')
15+
16+
+ set the initial state to an empty object
17+
@test('06/05')

tutorial/07/01.js

Whitespace-only changes.

tutorial/07/02.js

Whitespace-only changes.

tutorial/07/index.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## Middleware
2+
Using thunks for async actions.
3+
4+
+ import `applyMiddleware`
5+
@test('07/01')
6+
7+
+ set the second param in createStore to `applyMiddleware()`
8+
@test('07/02')
9+
10+
+ install "redux-logger" using npm
11+
@test('07/03')
12+
13+
+ create a "logger" as the result of `createLogger()`
14+
@test('07/04')
15+
16+
+ pass "logger" into `applyMiddleware()`
17+
@test('07/05')
18+
19+
@onPageComplete('Look in the console')

tutorial/08/01.js

Whitespace-only changes.

tutorial/08/02.js

Whitespace-only changes.

tutorial/08/03.js

Whitespace-only changes.

tutorial/08/04.js

Whitespace-only changes.

tutorial/08/05.js

Whitespace-only changes.

tutorial/08/06.js

Whitespace-only changes.

tutorial/08/07.js

Whitespace-only changes.

tutorial/08/08.js

Whitespace-only changes.

tutorial/08/index.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
## Second Action
2+
Creating a "SORT_BY_POPULARITY" action.
3+
4+
```js
5+
function sortByVotes(a, b) {
6+
switch(true) {
7+
case a.votes < b.votes:
8+
return 1;
9+
case a.votes > b.votes:
10+
return -1;
11+
default:
12+
return 0;
13+
}
14+
}
15+
```
16+
17+
Sort pokemon by votes
18+
19+
+ create an action type for 'SORT_BY_POPULARITY'
20+
@test('08/01')
21+
22+
+ create an action creator called 'sortByPopularity'
23+
@test('08/02')
24+
25+
+ dispatch a `sortByPopularity` action after the two voteUp dispatches
26+
@test('08/03')
27+
28+
+ add a `SORT_BY_POPULARITY` case that returns `pokemon.sort();`
29+
@test('08/04')
30+
31+
+ create a sortByVotes function and pass it into the pokemon.sort function
32+
@test('08/05')
33+
34+
+ Make a `sortByKey` function, which is more reusable, by wrapping it in a function that takes a key
35+
@test('08/06')
36+
37+
+ You've just created a **thunk** - a function that returns a function. Pass your function into the pokemon.sort() method and give it the key of 'votes'
38+
@test('08/07')
39+
40+
@onPageComplete('In the next step, we'll look at using thunks to call async actions')

tutorial/09/01.js

Whitespace-only changes.

tutorial/09/02.js

Whitespace-only changes.

tutorial/09/03.js

Whitespace-only changes.

tutorial/09/04.js

Whitespace-only changes.

tutorial/09/05.js

Whitespace-only changes.

tutorial/09/06.js

Whitespace-only changes.

0 commit comments

Comments
 (0)