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.

0 commit comments

Comments
 (0)