文章目录
前言
学习Redux第一天(基于angular的简易的小demo-实现组件间通讯)
一、toDoList
代码下载地址:https://github.com/fairyLiu-153/angular-redux
先看组件分布,最外层组件父组件(红框),add-to-do组件(蓝框), doing组件(黑框),done组件(紫框),
这次我还是先写redux部分,然后就开始分析:
- state:要分析结构的哈,首先我页面渲染需要什么数据,数据的结构,做啥事?比如吃饭睡觉,那就需要一个text属性,完成了吗?完成了就在done表显示,没完成就在doing表显示,就需要一个completed属性。那最基本的就定下来了。
- action: 然后我就想action需要有几个type,得有增加add,切换toggle,删除delete,最最基本的是这仨。
- reducer: 接着我又想,若想实现add,toggle,delete功能,我分别需要什么数据,比如add,那我就需要add的内容text,toggle我得需要toggle的哪一条,那条item,删除也是,我删除哪一条,要么我得知道这一条是哪一条,要么我得知道它的索引来把它删掉,这样,参数就基本定下来了
以上,我终于想完了,不啰嗦了,那我开始写吧。下面附上完整代码:
二、代码
- 目录结构(看to-do-list相关即可)
- 代码展示
1.to-do-list.action.ts
import { Action, ActionCreator } from 'redux';
import { ITodoItem } from '../reducers/to-do-list.reducer';
export const ADD_TODO = 'ADD_TODO';
export const TOGGLE_TODO = 'TOGGLE_TODO';
export const DELETE_TODO = 'DELETE_TODO';
// add todo
export interface AddToDoAction extends Action {
text: string;
}
export const addTodo: ActionCreator<AddToDoAction> = (text: string) => ({
type: ADD_TODO,
text
});
// toggle todo
export interface ToggleToDoAction extends Action {
todoItem: ITodoItem;
}
export const toggleToDo: ActionCreator<ToggleToDoAction> = (todoItem: ITodoItem) => ({
type: TOGGLE_TODO,
todoItem
});
// delete todo
export interface DeleteToDoAction extends Action {
todoItem: ITodoItem;
}
export const deleteToDo: ActionCreator<ToggleToDoAction> = (todoItem: ITodoItem) => ({
type: DELETE_TODO,
todoItem
});
2.actions目录下index.ts
import * as LoginActions from './login.action';
import * as TodoListActions from './to-do-list.action';
export {
LoginActions,
TodoListActions
}
3.to-do-list.reducer.ts
import { Action } from 'redux';
import * as _ from 'lodash';
import { AddToDoAction, ToggleToDoAction, DeleteToDoAction } from '../actions/to-do-list.action';
export interface ITodoItem {
text: string;
completed: boolean;
}
export interface ToDosState {
todos: ITodoItem[];
}
export const initialState: ToDosState = {
todos: []
};
export const ToDosReducer = function (state: ToDosState = initialState, action: Action) {
let todoList: ITodoItem[];
let todoItem: ITodoItem = {
text: '',
completed: false
};
switch (action.type) {
case 'ADD_TODO':
todoList = state.todos;
todoItem.text = (action as AddToDoAction).text;
todoItem.completed = false;
return Object.assign({todos: [...todoList, todoItem]});
case 'TOGGLE_TODO': {
todoList = state.todos;
todoItem = (action as ToggleToDoAction).todoItem;
todoItem.completed = !todoItem.completed;
return Object.assign({todos: [...todoList]});
}
case 'DELETE_TODO': {
todoList = state.todos;
todoItem = (action as DeleteToDoAction).todoItem;
return Object.assign({}, state, {
todos: _.reject(todoList, todo => todo === todoItem)
});
}
default:
return state;
}
};
4.reducers目录下index.ts
import { Reducer, combineReducers } from 'redux';
import { LoginState, LoginReducer } from './login.reducer';
export * from './login.reducer';
import { ToDosState, ToDosReducer } from './to-do-list.reducer';
export * from './to-do-list.reducer';
export interface AppState {
login: LoginState;
toDoList: ToDosState;
}
export const rootReducer: Reducer<AppState> = combineReducers<AppState>({
login: LoginReducer,
toDoList: ToDosReducer
});
5.redux.service.ts
import { Injectable } from '@angular/core';
import { createStore, Store, Unsubscribe } from 'redux';
import { AppState, rootReducer} from './reducers';
import { LoginState } from './reducers/login.reducer';
import { ITodoItem, ToDosState } from './reducers/to-do-list.reducer';
import { TodoListActions, LoginActions } from './actions';
@Injectable({
providedIn: 'root'
})
export class ReduxService {
private store: Store<AppState>;
private unsubscribe: Unsubscribe;
constructor() {
// 创建redux store 来存放应用的状态
this.store = createStore(
rootReducer
);
}
// 读取状态
getIsLogin(): boolean {
const state: LoginState = this.store.getState().login;
return state.login;
}
// 改变内部state -> dispatch一个action
setIsLogin(login: boolean) {
this.store.dispatch(LoginActions.setIsLogin(login));
}
// 订阅更新
subscribeStore(readStateFun: () => void) {
this.unsubscribe = this.store.subscribe(readStateFun);
}
getTodoList() {
const todoState: ToDosState = this.store.getState().toDoList;
return todoState;
}
addTodo(text: string) {
this.store.dispatch((TodoListActions.addTodo(text)));
}
deleteTodo(todoItem: ITodoItem) {
this.store.dispatch(TodoListActions.deleteToDo(todoItem));
}
toggleTodo(todoItem: ITodoItem) {
this.store.dispatch(TodoListActions.toggleToDo(todoItem));
}
}
6.to-do-list.component.html
<app-add-todo></app-add-todo>
<h6>doing:</h6>
<hr>
<app-doing></app-doing>
<br>
<br>
<h6>done:</h6>
<hr>
<app-done></app-done>
7.add-todo.component.html
<form [formGroup]="myForm">
<input type="text" placeholder="to do" formControlName="todo">
<button (click)="addTodo()">add</button>
</form>
8.add-todo.component.ts
import { Component, OnInit } from '@angular/core';
import { ReduxService } from 'src/app/redux/redux.service';
import { AstMemoryEfficientTransformer } from '@angular/compiler';
import { FormGroup, FormBuilder } from '@angular/forms';
@Component({
selector: 'app-add-todo',
templateUrl: './add-todo.component.html',
styleUrls: ['./add-todo.component.scss']
})
export class AddTodoComponent implements OnInit {
myForm: FormGroup;
constructor(
private reduxService: ReduxService,
private fb: FormBuilder
) {
this.myForm = this.fb.group({
todo: ['']
});
}
ngOnInit(): void {
}
addTodo() {
const text = this.myForm.controls.todo.value;
this.reduxService.addTodo(text);
this.myForm.controls.todo.setValue('');
}
}
9.doing.component.html
<ul>
<li *ngFor="let item of list" style="display: flex; justify-content: space-between;">
<span>* {{item.text}}</span>
<div>
<button (click)="toggle(item)">toggle</button>
<button (click)="delete(item)">delete</button>
</div>
</li>
</ul>
9.doing.component.ts
import { Component, OnInit } from '@angular/core';
import { ReduxService } from 'src/app/redux/redux.service';
import { ITodoItem } from 'src/app/redux/reducers';
import * as _ from 'lodash';
@Component({
selector: 'app-doing',
templateUrl: './doing.component.html',
styleUrls: ['./doing.component.scss']
})
export class DoingComponent implements OnInit {
list: ITodoItem[];
allList: ITodoItem[];
constructor(
private reduxService: ReduxService
) { }
ngOnInit(): void {
this.readState();
this.reduxService.subscribeStore(() => { this.readState(); });
}
readState() {
this.getTodoLists();
}
getTodoLists() {
this.allList = this.reduxService.getTodoList().todos;
this.list = _.filter(this.allList, item => item.completed === false);
}
delete(item: ITodoItem) {
this.reduxService.deleteTodo(item);
}
toggle(item: ITodoItem) {
this.reduxService.toggleTodo(item);
}
}
8.done.component.html
<ul>
<li *ngFor="let item of list" style="display: flex; justify-content: space-between;">
<span>* {{item.text}}</span>
<div>
<button (click)="toggle(item)">toggle</button>
<button (click)="delete(item)">delete</button>
</div>
</li>
</ul>
9.done.component.ts
import { Component, OnInit } from '@angular/core';
import { ITodoItem } from 'src/app/redux/reducers';
import { ReduxService } from 'src/app/redux/redux.service';
import * as _ from 'lodash';
@Component({
selector: 'app-done',
templateUrl: './done.component.html',
styleUrls: ['./done.component.scss']
})
export class DoneComponent implements OnInit {
list: ITodoItem[];
allList: ITodoItem[];
constructor(
private reduxService: ReduxService
) {
}
ngOnInit(): void {
this.readState();
this.reduxService.subscribeStore(() => { this.readState(); });
}
readState() {
this.getTodoLists();
}
getTodoLists() {
this.allList = this.reduxService.getTodoList().todos;
this.list = _.filter(this.allList, item => item.completed === true)
}
delete(item: ITodoItem) {
this.reduxService.deleteTodo(item);
}
toggle(item: ITodoItem) {
this.reduxService.toggleTodo(item);
}
}
总结
其实,有了redux第一天的学习,做这个demo非常的简单,理清楚思路写就是了,不需要父子组件来回传参,redux可以更好的帮我们组件交互,基本上写完redux想做了功能也完成的差不多了。