Skip to content

Commit d010992

Browse files
committed
Step 5 outline and tests complete
1 parent 1adc1d3 commit d010992

File tree

8 files changed

+94
-63
lines changed

8 files changed

+94
-63
lines changed

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ A [CodeRoad](https://coderoad.github.io) tutorial for learning Redux.
55
<!-- @import('01') -->
66
<!-- @import('02') -->
77
<!-- @import('03') -->
8-
<!-- @import('05') -->
8+
<!-- @import('04') -->
99
<!-- @import('06') -->
1010
<!-- @import('07') -->
1111
<!-- @import('08') -->
@@ -28,13 +28,21 @@ CodeRoad is an open-sourced interactive tutorial platform for the Atom Editor. L
2828

2929
## Outline
3030

31-
##### Reducer
31+
##### Pure Functions
3232

33-
The data transformation
33+
Reducers must be pure functions
3434

35+
State is "read only".
36+
37+
Notes
3538
```js
36-
const reducer = (state) => {
37-
console.log(state);
38-
return state;
39-
};
40-
```
39+
const nextPokemon = state.pokemon.map(p => {
40+
if (id === p.id) {
41+
p.votes += 1;
42+
}
43+
return p;
44+
});
45+
return {
46+
pokemon: nextPokemon
47+
};
48+
```

coderoad.json

Lines changed: 14 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,36 @@
11
{
22
"info": {
33
"title": "CodeRoad Redux JS Tutorial",
4-
"description": "A [CodeRoad](https://coderoad.github.io) tutorial for learning Redux.\n\n<!-- @import('01') -->\n<!-- @import('02') -->\n<!-- @import('03') -->\n<!-- @import('05') -->\n<!-- @import('06') -->\n<!-- @import('07') -->\n<!-- @import('08') -->\n<!-- @import('09') -->"
4+
"description": "A [CodeRoad](https://coderoad.github.io) tutorial for learning Redux.\n\n<!-- @import('01') -->\n<!-- @import('02') -->\n<!-- @import('03') -->\n<!-- @import('04') -->\n<!-- @import('06') -->\n<!-- @import('07') -->\n<!-- @import('08') -->\n<!-- @import('09') -->"
55
},
66
"pages": [
77
{
8-
"title": "Reducer",
9-
"description": "The data transformation\n\n```js\nconst reducer = (state) => {\n console.log(state);\n return state;\n};\n```",
8+
"title": "Pure Functions",
9+
"description": "Reducers must be pure functions\n\nState is \"read only\".\n\nNotes\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 ```",
1010
"tasks": [
1111
{
12-
"description": "Extract the `state => state` function in create store, and call in a new function called \"reducer\".",
12+
"description": "Return a new list of Pokemon after incrementing \"votes\" of the pokemon with the matching \"id\"",
1313
"tests": [
14-
"04/01"
15-
],
16-
"actions": [
17-
"open('index.js')"
18-
]
19-
},
20-
{
21-
"description": "Log the state inside of your reducer. What does it look like?",
22-
"tests": [
23-
"04/02"
24-
],
25-
"hints": [
26-
"Add a `console.log` statement inside of your reducer function",
27-
"Try this:```js\nconst reducer = (state) => {\n console.log(state);\n return state;\n};\n```"
28-
]
29-
},
30-
{
31-
"description": "Pass an action as a second param to the reducer",
32-
"tests": [
33-
"04/03"
14+
"05/01"
3415
]
3516
},
3617
{
37-
"description": "Dispatch two voteUp actions through the reducer: `store.dispatch(voteUp(2))`. Change your log statement inside of your reducer to look like this: `console.log('state: ', state, 'action: ', action)`",
18+
"description": "Let's make a test to see that we are truly returning a new state. Wrap your `initialState` object in a `Object.freeze`. Freeze makes an object unchangeable. And yet your reducer should still work.",
3819
"tests": [
39-
"04/04"
20+
"05/02"
4021
]
4122
},
4223
{
43-
"description": "Create a `switch` statement and pass in `action.type`, the default return should return `state`",
24+
"description": "What if we were dealing with multiple keys on the state. We'd have to ensure that our changes return a complete new state each time. Use `Object.assign`",
4425
"tests": [
45-
"04/05"
46-
]
47-
},
48-
{
49-
"description": "The `switch` statement should have a `default` case that returns the state",
50-
"tests": [
51-
"04/06"
52-
]
53-
},
54-
{
55-
"description": "add a switch case for `VOTE_UP`. For now, just console.log the `id` of the action passed in and return the default state again.",
56-
"tests": [
57-
"04/07"
26+
"05/03"
27+
],
28+
"hints": [
29+
"return `Object.assign({}, { pokemon: nextPokemon });`"
5830
]
5931
}
60-
]
32+
],
33+
"onPageComplete": "Now that you have an idea of how reducers work. Next we can look at how to create multiple, modular reducers."
6134
}
6235
]
6336
}

tutorial/04/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ const reducer = (state) => {
3636
+ The `switch` statement should have a `default` case that returns the state
3737
@test('04/06')
3838

39-
+ add a switch case for `VOTE_UP`. For now, just console.log the `id` of the action passed in and return the default state again.
39+
+ add a switch case for `VOTE_UP`. For now, just console.log the `id` of the action passed in and return the default state again. Tip: destructuring: `const { id } = action.payload;`
4040
@test('04/07')

tutorial/05/01.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1-
describe('01 pure function', () => {
1+
var expect = require('chai').expect;
2+
3+
/// load('index.js')
4+
5+
describe('01 the pure reducer', () => {
6+
7+
const testState = {
8+
pokemon: [{
9+
id: 99,
10+
votes: 0,
11+
}, {
12+
id: 100,
13+
votes: 0,
14+
}, {
15+
id: 101,
16+
votes: 0,
17+
}]
18+
};
19+
20+
const testAction = ({ type: 'VOTE_UP', payload: { id: 100 } });
21+
22+
it('should have a reducer', () => {
23+
expect(reducer).to.be.defined;
24+
})
25+
26+
it('should increment the votes matching the id only', () => {
27+
expect(reducer(testState, testAction).pokemon[1].votes).to.equal(1);
28+
});
229

330
});

tutorial/05/02.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1-
describe('02 pure function', () => {
1+
describe('02 initialState', () => {
2+
3+
it('should be frozen', () => {
4+
expect(Object.isFrozen(initialState)).to.be.true;
5+
});
26

37
});

tutorial/05/03.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
describe('03 uses Object.assign', () => {
2+
3+
it('to return the modified state', () => {
4+
const regex = /Object.assign/;
5+
const string = reducer.toString();
6+
expect(string).to.match(regex);
7+
});
8+
9+
it('to target an empty object', () => {
10+
const regex = /Object.assign\(\{\}\,/;
11+
const string = reducer.toString();
12+
expect(string).to.match(regex);
13+
});
14+
15+
});

tutorial/05/index.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
# Pure Functions
1+
## Pure Functions
2+
Reducers must be pure functions
23

3-
05/01
4+
State is "read only".
5+
6+
Notes
47
```js
58
const nextPokemon = state.pokemon.map(p => {
69
if (id === p.id) {
@@ -13,13 +16,14 @@ const nextPokemon = state.pokemon.map(p => {
1316
};
1417
```
1518

16-
+ Return a new list of Pokemon with the pokemon matching the id incrementing its votes by one
19+
+ Return a new list of Pokemon after incrementing "votes" of the pokemon with the matching "id"
1720
@test('05/01')
1821

19-
20-
21-
+ Use Object.assign
22+
+ Let's make a test to see that we are truly returning a new state. Call `Object.freeze()` on your `initialState`. `freeze` makes an object immutable - meaning the object can not be changed. And yet your reducer should still work, since it returns a new state each call.
2223
@test('05/02')
24+
25+
+ What if we were dealing with multiple keys on the state. We'd have to ensure that our changes return a complete new state each time. Use `Object.assign`
26+
@test('05/03')
2327
@hint('return `Object.assign({}, { pokemon: nextPokemon });`')
2428

25-
@onPageComplete('')
29+
@onPageComplete('Now that you have an idea of how reducers work. Next we can look at how to create multiple, modular reducers.')

tutorial/tutorial.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
A [CodeRoad](https://coderoad.github.io) tutorial for learning Redux.
44

5-
<!-- @import('01') -->
6-
<!-- @import('02') -->
7-
<!-- @import('03') -->
5+
@import('01')
6+
@import('02')
7+
@import('03')
88
@import('04')
9-
<!-- @import('05') -->
9+
@import('05')
1010
<!-- @import('06') -->
1111
<!-- @import('07') -->
1212
<!-- @import('08') -->

0 commit comments

Comments
 (0)