step 6 exercise

This commit is contained in:
Ken
2019-02-19 22:20:09 -08:00
parent 2b41788cc2
commit 72ace4f43c
12 changed files with 39 additions and 159 deletions

View File

@@ -108,10 +108,11 @@
</div>
</li>
<li class="Tile">
<a target="_blank" href="/step2-06/" class="Tile-link">
<div class="Tile-link">
Step 6<br />
Redux: Dispatch Actions
</a>
<div><a target="_blank" href="/step2-06/demo/">demo</a> | <a target="_blank" href="/step2-06/exercise/">exercise</a></div>
</div>
</li>
<li class="Tile">
<a target="_blank" href="/step2-07/" class="Tile-link">

View File

@@ -16,6 +16,6 @@ From the official documentation site:
2. Open `exercise/src/reducers/pureFunctions.ts` and fill in the missing body of the pure functions.
3. Open `exercise/src/reducers/index.ts` and observe how those pureFunctions are called.
3. Open `exercise/src/reducers/index.ts` and fill in the missing case statements for the switch of `action.type`.
4. Open `exercise/src/reducers/pureFunctions.spec.ts` and implement tests for the functions you wrote for `remove`, `complete`, and `clear`.

View File

@@ -1,19 +1,15 @@
import { Store } from '../store';
import { addTodo, remove, complete, clear } from './pureFunctions';
import { addTodo, remove, complete } from './pureFunctions';
export function reducer(state: Store['todos'], payload: any): Store['todos'] {
switch (payload.type) {
case 'addTodo':
return addTodo(state, payload.id, payload.label);
case 'remove':
return remove(state, payload.id);
case 'complete':
return complete(state, payload.id);
case 'clear':
return clear(state);
// Fill in the blanks here for:
// - remove
// - complete
// - clear
}
return state;

View File

@@ -1,3 +1,15 @@
# Step 2.6
Dispatching Actions and Examining State
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 saw how we may compose the reducers according to the shape
# Exercise
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

@@ -1,10 +1,20 @@
import { createStore } from 'redux';
import { reducer } from '.';
import { actions } from '../actions';
describe('reducers', () => {
it('should listen to addTodo message', () => {
const store = createStoreWithDevTool(reducer, {});
console.log(store.getState());
store.dispatch(actions.addTodo('hello'));
store.dispatch(actions.addTodo('world'));
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

@@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<div id="app"></div>
</body>
</html>

View File

@@ -1,8 +0,0 @@
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

@@ -1,19 +0,0 @@
import { reducer } from './reducers';
import { createStore, compose } from 'redux';
import { actions } from './actions';
/* Goop for making the Redux dev tool to work */
declare var window: any;
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
function createStoreWithDevTool(reducer, initialStore) {
return createStore(reducer, initialStore, composeEnhancers());
}
const store = createStoreWithDevTool(reducer, {});
console.log(store.getState());
store.dispatch(actions.addTodo('hello'));
store.dispatch(actions.addTodo('world'));
console.log(store.getState());

View File

@@ -1,27 +0,0 @@
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

@@ -1,29 +0,0 @@
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

@@ -1,36 +0,0 @@
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

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