adding docs subtree

This commit is contained in:
Micah Godbolt
2019-02-25 13:12:18 -08:00
parent 1adcc07a61
commit 41dcf8731d
365 changed files with 10620 additions and 0 deletions

30
docs/step2-06/README.md Normal file
View File

@@ -0,0 +1,30 @@
# Step 2.6
[Lessons](../) | [Exercise](./exercise/) | [Demo](./demo/)
Redux: Dispatching Actions and Examining State.
In this step, we learn about `dispatch` and `getState()`. Dispatching action messages to the store is the only means by which to inform the reducers to modify the shared state tree.
We also see how we may compose the reducers according to the shape.
If you want a really neat UI to show what the store looks when actions are dispatched to the store, use this Chrome extension:
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd
# Exercise
## Visualize the state changes with Chrome extension
1. Install [Chrome extension](https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd)
2. Open the inspector panel entitled **Redux**
3. Modify `exercise/src/index.tsx` to dispatch actions
## Playing with dispatching actions inside tests
1. open the `exercise/src/reducers/reducer.spec.ts`
2. Follow the instructions to fill out the reducer tests
3. Run the tests with `npm test`

View File

@@ -0,0 +1 @@
<!doctype html><html><head><link rel="stylesheet" href="../../assets/step.css"></head><body class="ms-Fabric"><div id="markdownReadme"></div><div id="app">For this step, we look at unit testing. Run<pre>npm test</pre>in the command line.</div><script src="../../step2-06/demo/step2-06/demo.js"></script><script src="../../markdownReadme/markdownReadme.js"></script></body></html>

View File

@@ -0,0 +1,8 @@
import uuid from 'uuid/v4';
export const actions = {
addTodo: (label: string) => ({ type: 'addTodo', id: uuid(), label }),
remove: (id: string) => ({ type: 'remove', id }),
complete: (id: string) => ({ type: 'complete', id }),
clear: () => ({ type: 'clear' })
};

View File

@@ -0,0 +1,13 @@
import { reducer } from './reducers';
import { createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { actions } from './actions';
const store = createStore(reducer, {}, composeWithDevTools());
console.log(store.getState());
store.dispatch(actions.addTodo('hello'));
store.dispatch(actions.addTodo('world'));
console.log(store.getState());

View File

@@ -0,0 +1,27 @@
import { Store } from '../store';
import { addTodo, remove, complete, clear } from './pureFunctions';
function todoReducer(state: Store['todos'] = {}, action: any): Store['todos'] {
switch (action.type) {
case 'addTodo':
return addTodo(state, action.id, action.label);
case 'remove':
return remove(state, action.id);
case 'clear':
return clear(state);
case 'complete':
return complete(state, action.id);
}
return state;
}
export function reducer(state: Store, action: any): Store {
return {
todos: todoReducer(state.todos, action),
filter: 'all'
};
}

View File

@@ -0,0 +1,29 @@
import { addTodo, complete } from './pureFunctions';
import { Store } from '../store';
describe('TodoApp reducers', () => {
it('can add an item', () => {
const state = <Store['todos']>{};
const newState = addTodo(state, '0', 'item1');
const keys = Object.keys(newState);
expect(newState).not.toBe(state);
expect(keys.length).toBe(1);
expect(newState[keys[0]].label).toBe('item1');
expect(newState[keys[0]].completed).toBeFalsy();
});
it('can complete an item', () => {
const state = <Store['todos']>{};
let newState = addTodo(state, '0', 'item1');
const key = Object.keys(newState)[0];
newState = complete(newState, key);
expect(newState[key].completed).toBeTruthy();
});
});

View File

@@ -0,0 +1,36 @@
import { Store, FilterTypes } from '../store';
export function addTodo(state: Store['todos'], id: string, label: string): Store['todos'] {
return { ...state, [id]: { label, completed: false } };
}
export function remove(state: Store['todos'], id: string) {
const newTodos = { ...state };
delete newTodos[id];
return newTodos;
}
export function complete(state: Store['todos'], id: string) {
const newTodos = { ...state };
newTodos[id].completed = !newTodos[id].completed;
return newTodos;
}
export function clear(state: Store['todos']) {
const newTodos = { ...state };
Object.keys(state.todos).forEach(key => {
if (state.todos[key].completed) {
delete newTodos[key];
}
});
return newTodos;
}
export function setFilter(state: Store['filter'], filter: FilterTypes) {
return filter;
}

View File

@@ -0,0 +1,14 @@
export type FilterTypes = 'all' | 'active' | 'completed';
export interface TodoItem {
label: string;
completed: boolean;
}
export interface Store {
todos: {
[id: string]: TodoItem;
};
filter: FilterTypes;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
<!doctype html><html><head><link rel="stylesheet" href="../../assets/step.css"></head><body class="ms-Fabric"><div id="markdownReadme"></div><div id="app">For this step, we look at unit testing. Run<pre>npm test</pre>in the command line.</div><script src="../../step2-06/exercise/step2-06/exercise.js"></script><script src="../../markdownReadme/markdownReadme.js"></script></body></html>

View File

@@ -0,0 +1,5 @@
import uuid from 'uuid/v4';
export const actions = {
addTodo: (label: string) => ({ type: 'addTodo', id: uuid(), label })
};

View File

@@ -0,0 +1,18 @@
import { reducer } from './reducers';
import { createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { actions } from './actions';
const store = createStore(reducer, {}, composeWithDevTools());
console.log(store.getState());
/*
TODO: dispatch several actions and see the effect to the state inside the Redux devtool
store.dispatch(actions.???);
store.dispatch(actions.???);
store.dispatch(actions.???);
*/
console.log(store.getState());

View File

@@ -0,0 +1,27 @@
import { Store } from '../store';
import { addTodo, remove, complete, clear } from './pureFunctions';
function todoReducer(state: Store['todos'] = {}, action: any): Store['todos'] {
switch (action.type) {
case 'addTodo':
return addTodo(state, action.id, action.label);
case 'remove':
return remove(state, action.id);
case 'clear':
return clear(state);
case 'complete':
return complete(state, action.id);
}
return state;
}
export function reducer(state: Store, action: any): Store {
return {
todos: todoReducer(state.todos, action),
filter: 'all'
};
}

View File

@@ -0,0 +1,29 @@
import { addTodo, complete } from './pureFunctions';
import { Store } from '../store';
describe('TodoApp reducers', () => {
it('can add an item', () => {
const state = <Store['todos']>{};
const newState = addTodo(state, '0', 'item1');
const keys = Object.keys(newState);
expect(newState).not.toBe(state);
expect(keys.length).toBe(1);
expect(newState[keys[0]].label).toBe('item1');
expect(newState[keys[0]].completed).toBeFalsy();
});
it('can complete an item', () => {
const state = <Store['todos']>{};
let newState = addTodo(state, '0', 'item1');
const key = Object.keys(newState)[0];
newState = complete(newState, key);
expect(newState[key].completed).toBeTruthy();
});
});

View File

@@ -0,0 +1,36 @@
import { Store, FilterTypes } from '../store';
export function addTodo(state: Store['todos'], id: string, label: string): Store['todos'] {
return { ...state, [id]: { label, completed: false } };
}
export function remove(state: Store['todos'], id: string) {
const newTodos = { ...state };
delete newTodos[id];
return newTodos;
}
export function complete(state: Store['todos'], id: string) {
const newTodos = { ...state };
newTodos[id].completed = !newTodos[id].completed;
return newTodos;
}
export function clear(state: Store['todos']) {
const newTodos = { ...state };
Object.keys(state.todos).forEach(key => {
if (state.todos[key].completed) {
delete newTodos[key];
}
});
return newTodos;
}
export function setFilter(state: Store['filter'], filter: FilterTypes) {
return filter;
}

View File

@@ -0,0 +1,20 @@
import { createStore } from 'redux';
import { reducer } from '.';
import { actions } from '../actions';
describe('reducers', () => {
it('should add items', () => {
// 1. use Redux's createStore() to create a store with reducer as argument
// along with the initial state
//
// 2. call store.dispatch() with some action messages to indicate the kind of
// action to perform (in this case, addTodo)
//
// 3. assert with expect() on the resultant store.getState().todos
});
// Tests left for you to do:
// - remove
// - clear
// - complete
});

View File

@@ -0,0 +1,14 @@
export type FilterTypes = 'all' | 'active' | 'completed';
export interface TodoItem {
label: string;
completed: boolean;
}
export interface Store {
todos: {
[id: string]: TodoItem;
};
filter: FilterTypes;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long