got add, remove, and edit actions working

This commit is contained in:
Ken 2019-02-01 09:47:04 -08:00
Родитель 260b6177fe
Коммит 0e0ea2ef06
9 изменённых файлов: 860 добавлений и 108 удалений

757
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -4,19 +4,27 @@
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --mode development --progress",
"start:client": "webpack-dev-server --mode development --progress",
"build": "webpack --mode production",
"test": "jest --watch"
"test": "jest --watch",
"start:server": "nodemon server/index.js",
"start": "run-p start:server start:client"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/express": "^4.16.1",
"@types/body-parser": "^1.17.0",
"@types/node": "~10.12.21",
"@types/jest": "^23.3.13",
"@types/react": "^16.7.20",
"@types/react-dom": "^16.0.11",
"@types/react-redux": "^7.0.0",
"@types/redux": "^3.6.0",
"@types/cors": "^2.8.4",
"body-parser": "^1.18.3",
"cors": "^2.8.5",
"html-webpack-plugin": "^3.2.0",
"jest": "^23.6.0",
"ts-jest": "^23.10.5",
@ -24,15 +32,19 @@
"typescript": "^3.2.4",
"webpack": "^4.28.4",
"webpack-cli": "^3.2.1",
"webpack-dev-server": "^3.1.14"
"webpack-dev-server": "^3.1.14",
"npm-run-all": "^4.1.5",
"nodemon": "^1.18.9"
},
"dependencies": {
"office-ui-fabric-react": "^6.128.0",
"@uifabric/experiments": "^6.51.1",
"express": "^4.16.4",
"immer": "^1.12.1",
"office-ui-fabric-react": "^6.128.0",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"redux": "^4.0.1",
"react-redux": "^6.0.0",
"immer": "^1.12.1"
"redux-thunk": "^2.3.0",
"redux": "^4.0.1"
}
}

Просмотреть файл

@ -1,7 +1,12 @@
import { action, GenericActionTypes, GenericAction, GenericActionLookup } from '../redux-utils/action';
import { Dispatch } from 'redux';
import { Store } from '../store';
import * as todosService from '../service/todosService';
let counter = 0;
export const actions = {
add: (label: string) => action('add', { label }),
add: (label: string) => action('add', { id: String(counter++), label }),
remove: (id: string) => action('remove', { id }),
edit: (id: string, label: string) => action('edit', { id, label }),
complete: (id: string) => action('complete', { id }),
@ -9,6 +14,46 @@ export const actions = {
filter: (filterTypes: string) => action('filter', { filter: filterTypes })
};
export const actionsWithService = {
add: (label: string) => {
return async (dispatch: Dispatch<TodoAction>, getState: () => Store) => {
const addAction = actions.add(label);
const id = addAction.id;
dispatch(addAction);
await todosService.add(id, getState().todos[id]);
};
},
edit: (id: string, label: string) => {
return async (dispatch: Dispatch<TodoAction>, getState: () => Store) => {
dispatch(actions.edit(id, label));
await todosService.edit(id, getState().todos[id]);
};
},
remove: (id: string) => {
return async (dispatch: Dispatch<TodoAction>, getState: () => Store) => {
dispatch(actions.remove(id));
await todosService.remove(id);
};
},
complete: (id: string) => {
return async (dispatch: Dispatch<TodoAction>, getState: () => Store) => {
dispatch(actions.complete(id));
await todosService.edit(id, getState().todos[id]);
};
},
clear: () => {
return async (dispatch: Dispatch<TodoAction>, getState: () => Store) => {
dispatch(actions.clear());
await todosService.editBulk(getState().todos);
};
}
};
export type ActionTypes = GenericActionTypes<typeof actions>;
export type TodoAction = GenericAction<typeof actions>;
export type TodoActionWithService = GenericAction<typeof actionsWithService>;
export type TodoActionLookup = GenericActionLookup<typeof actions>;

Просмотреть файл

@ -1,4 +1,4 @@
import { actions, TodoAction } from '../actions';
import { actions, actionsWithService } from '../actions';
import { Store, FilterTypes } from '../store';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
@ -11,12 +11,12 @@ export function mapStateToProps({ todos, filter }: Store) {
};
}
export function mapDispatchToProps(dispatch: Dispatch<TodoAction>) {
export function mapDispatchToProps(dispatch: any) {
return {
add: (label: string) => dispatch(actions.add(label)),
remove: (id: string) => dispatch(actions.remove(id)),
complete: (id: string) => dispatch(actions.complete(id)),
edit: (id: string, label: string) => dispatch(actions.edit(id, label)),
add: (label: string) => dispatch(actionsWithService.add(label)),
remove: (id: string) => dispatch(actionsWithService.remove(id)),
complete: (id: string) => dispatch(actionsWithService.complete(id)),
edit: (id: string, label: string) => dispatch(actionsWithService.edit(id, label)),
clear: () => dispatch(actions.clear()),
setFilter: (filter: FilterTypes) => dispatch(actions.filter(filter))
};

Просмотреть файл

@ -1,18 +1,36 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import { reducer } from './reducers';
import { TodoAppContainer } from './components/TodoAppContainer';
import { initializeIcons } from '@uifabric/icons';
import thunk from 'redux-thunk';
import * as todosService from './service/todosService';
import { FilterTypes } from './store';
declare var window: any;
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// For preloading store
initializeIcons();
ReactDOM.render(
<Provider store={store}>
<TodoAppContainer />
</Provider>,
document.getElementById('app')
);
(async () => {
const preloadStore = {
todos: await todosService.getAll(),
filter: 'all' as FilterTypes
};
const store = createStore(reducer, preloadStore, composeEnhancers(applyMiddleware(thunk)));
ReactDOM.render(
<Provider store={store}>
<TodoAppContainer />
</Provider>,
document.getElementById('app')
);
})();
// For Synchronous Case
// const store = createStore(reducer, { todos: {}, filter: 'all' }, composeEnhancers(applyMiddleware(thunk)));

Просмотреть файл

@ -2,15 +2,12 @@ import { createReducer } from './createReducer';
import { Store, FilterTypes } from '../store';
import { combineReducers } from 'redux';
let counter = 0;
export const reducer = combineReducers<Store>({
todos: createReducer<Store['todos']>(
{},
{
add(draft, action) {
const id = String(counter++);
draft[id] = { label: action.label, completed: false };
draft[action.id] = { label: action.label, completed: false };
return draft;
},

Просмотреть файл

@ -0,0 +1,48 @@
import { TodoItem, Store } from '../store';
const HOST = 'http://localhost:3000';
export async function add(id: string, todo: TodoItem) {
const response = await fetch(`${HOST}/todos/${id}`, {
method: 'post',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(todo)
});
return await response.json();
}
export async function edit(id: string, todo: TodoItem) {
const response = await fetch(`${HOST}/todos/${id}`, {
method: 'put',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(todo)
});
return await response.json();
}
export async function remove(id: string) {
const response = await fetch(`${HOST}/todos/${id}`, {
method: 'delete'
});
return await response.json();
}
export async function getAll() {
const response = await fetch(`${HOST}/todos`, {
method: 'get'
});
return await response.json();
}
export async function editBulk(todos: Store['todos']) {
const response = await fetch(`${HOST}/todos`, {
method: 'post',
headers: { 'content-type': 'application/json' },
body: JSON.stringify(todos)
});
return await response.json();
}

38
server/index.js Normal file
Просмотреть файл

@ -0,0 +1,38 @@
// @ts-check
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const app = express();
const store = {
/** @type {any} */
todos: {}
};
app.use(bodyParser.json());
app.use(cors());
app.get('/todos', (req, res) => {
res.json(store.todos);
});
app.put('/todos/:id', (req, res) => {
store.todos[req.params.id] = req.body;
res.json('ok');
});
app.post('/todos/:id', (req, res) => {
store.todos[req.params.id] = req.body;
});
app.delete('/todos/:id', (req, res) => {
delete store.todos[req.body.id];
});
app.post('/todos', (req, res) => {
store.todos = req.body;
});
app.listen(3000, () => {
console.log('Listening at http://localhost:3000');
});

Просмотреть файл

@ -7,6 +7,7 @@
"esModuleInterop": true,
"target": "es5",
"jsx": "react",
"allowJs": true
"allowJs": true,
"lib": ["es2015", "dom"]
}
}