integrating immer
This commit is contained in:
Родитель
a61d89ea14
Коммит
c44af2a38f
|
@ -3263,6 +3263,11 @@
|
|||
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
|
||||
"dev": true
|
||||
},
|
||||
"immer": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-1.12.1.tgz",
|
||||
"integrity": "sha512-3fmKM6ovaqDt0CdC9daXpNi5x/YCYS3i4cwLdTVkhJdk5jrDXoPs7lCm3IqM3yhfSnz4tjjxbRG2CziQ7m8ztg=="
|
||||
},
|
||||
"import-local": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server --mode development",
|
||||
"start": "webpack-dev-server --mode development --progress",
|
||||
"build": "webpack --mode production"
|
||||
},
|
||||
"keywords": [],
|
||||
|
@ -28,6 +28,7 @@
|
|||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"redux": "^4.0.1",
|
||||
"react-redux": "^6.0.0"
|
||||
"react-redux": "^6.0.0",
|
||||
"immer": "^1.12.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,18 +8,21 @@ import { TodoItem, FilterTypes } from '../store';
|
|||
export interface TodoAppProps {
|
||||
todos: { [id: string]: TodoItem };
|
||||
filter: FilterTypes;
|
||||
add: (label: string) => void;
|
||||
remove: (id: string) => void;
|
||||
setFilter: (filter: FilterTypes) => void;
|
||||
}
|
||||
|
||||
export class TodoApp extends React.Component<TodoAppProps> {
|
||||
render() {
|
||||
const { todos, filter } = this.props;
|
||||
const { todos, filter, add, remove, setFilter } = this.props;
|
||||
|
||||
return (
|
||||
<Stack horizontalAlign="center">
|
||||
<Stack style={{ width: 650 }} verticalGap={25}>
|
||||
<TodoHeader />
|
||||
<TodoHeader {...{ add, remove, filter }} />
|
||||
<TodoList {...{ todos, filter }} />
|
||||
<TodoFooter />
|
||||
<TodoFooter {...{ todos, setFilter }} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as actions from '../actions';
|
||||
import { Store } from '../store';
|
||||
import { Store, FilterTypes } from '../store';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { TodoApp } from './TodoApp';
|
||||
|
@ -14,7 +14,11 @@ export function mapStateToProps({ todos, filter }: Store) {
|
|||
export function mapDispatchToProps(dispatch: Dispatch<actions.TodoAction>) {
|
||||
return {
|
||||
add: (label: string) => dispatch(actions.add(label)),
|
||||
remove: (id: string) => dispatch(actions.remove(id))
|
||||
remove: (id: string) => dispatch(actions.remove(id)),
|
||||
complete: (id: string) => dispatch(actions.complete(id)),
|
||||
completeAll: () => dispatch(actions.completeAll()),
|
||||
clear: () => dispatch(actions.clear()),
|
||||
setFilter: (filter: FilterTypes) => dispatch(actions.filter(filter))
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,23 +1,54 @@
|
|||
import React from 'react';
|
||||
import { Text, Stack } from '@uifabric/experiments';
|
||||
import { Checkbox, Button, Pivot, PivotItem, TextField } from 'office-ui-fabric-react';
|
||||
import { Pivot, PivotItem, TextField } from 'office-ui-fabric-react';
|
||||
import { add } from '../actions';
|
||||
|
||||
export interface TodoFooterProps {}
|
||||
export interface TodoHeaderProps {
|
||||
add: (label: string) => void;
|
||||
remove: (id: string) => void;
|
||||
}
|
||||
|
||||
export const TodoHeader = (props: TodoFooterProps) => {
|
||||
return (
|
||||
<Stack>
|
||||
<Stack horizontal horizontalAlign="center">
|
||||
<Text variant="xxLarge">todos</Text>
|
||||
export interface TodoHeaderState {
|
||||
labelInput: string;
|
||||
}
|
||||
|
||||
export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState> {
|
||||
constructor(props: TodoHeaderProps) {
|
||||
super(props);
|
||||
this.state = { labelInput: undefined };
|
||||
}
|
||||
|
||||
onKeyPress = (evt: React.KeyboardEvent) => {
|
||||
if (evt.charCode === 13) {
|
||||
this.props.add(this.state.labelInput);
|
||||
this.setState({ labelInput: undefined });
|
||||
}
|
||||
};
|
||||
|
||||
onChange = (evt: React.FormEvent<HTMLInputElement>, newValue: string) => {
|
||||
this.setState({ labelInput: newValue });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Stack>
|
||||
<Stack horizontal horizontalAlign="center">
|
||||
<Text variant="xxLarge">todos</Text>
|
||||
</Stack>
|
||||
|
||||
<TextField
|
||||
placeholder="What needs to be done?"
|
||||
value={this.state.labelInput}
|
||||
onChange={this.onChange}
|
||||
onKeyPress={this.onKeyPress}
|
||||
/>
|
||||
|
||||
<Pivot>
|
||||
<PivotItem headerText="all" />
|
||||
<PivotItem headerText="active" />
|
||||
<PivotItem headerText="completed" />
|
||||
</Pivot>
|
||||
</Stack>
|
||||
|
||||
<TextField placeholder="What needs to be done?" />
|
||||
|
||||
<Pivot>
|
||||
<PivotItem headerText="all" />
|
||||
<PivotItem headerText="active" />
|
||||
<PivotItem headerText="completed" />
|
||||
</Pivot>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import { Reducer } from 'redux';
|
||||
import { ActionTypes, TodoAction } from '../actions';
|
||||
import { Draft, produce } from 'immer';
|
||||
|
||||
export function createReducer<T>(
|
||||
initialState: T,
|
||||
handlers: { [actionType in ActionTypes]?: (state: T, action: TodoAction) => T }
|
||||
handlers: { [actionType in ActionTypes]?: (state: Draft<T>, action: TodoAction) => T }
|
||||
): Reducer<T> {
|
||||
return function reducer(state = initialState, action: TodoAction): T {
|
||||
if (handlers.hasOwnProperty(action.type)) {
|
||||
return handlers[action.type](state, action);
|
||||
return produce(state, draft => handlers[action.type](draft, action));
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -5,17 +5,23 @@ import { combineReducers } from 'redux';
|
|||
let counter = 0;
|
||||
|
||||
export const reducer = combineReducers<Store>({
|
||||
todos: createReducer(
|
||||
todos: createReducer<Store['todos']>(
|
||||
{},
|
||||
{
|
||||
add(state, action) {
|
||||
add(draft, action) {
|
||||
const id = String(counter++);
|
||||
return { ...state, [id]: { label: action.label, completed: false } };
|
||||
draft[id] = { label: action.label, completed: false };
|
||||
return draft;
|
||||
},
|
||||
|
||||
remove(draft, action) {
|
||||
delete draft[action.id];
|
||||
return draft;
|
||||
}
|
||||
}
|
||||
),
|
||||
filter: createReducer<FilterTypes>('all', {
|
||||
filter(state, action) {
|
||||
filter(draft, action) {
|
||||
return action.filter;
|
||||
}
|
||||
})
|
||||
|
|
Загрузка…
Ссылка в новой задаче