我正在尝试通过创建 Todo 列表应用程序来使用 NgRx 学习 Angular 的反应状态。
为此,我首先创建两个主要组件
然后我为待办事项创建了一个界面。
export interface Todo {
id: string;
content: string;
}
然后开始做状态管理。首先,我创建了动作。我现在只关注 2 个操作,创建待办事项和删除待办事项。
import { createAction, props } from "@ngrx/store";
export const createTodo = createAction(
'[Add-Todo component] Add todo',
props<{ content: string }>()
)
export const deleteTodo = createAction(
'[Todo-List component] Delete todo',
props<{ id: string }>()
)
之后我开始研究减速器。我决定只做 create todo reducer,这样我就可以在担心删除之前在我的应用程序中显示一个列表。
import { Action, on, createReducer } from "@ngrx/store";
import { createTodo, deleteTodo } from "./todo.actions";
import { Todo } from "src/app/models/todo.model";
export interface todoState {
todos : Todo[];
}
export const initialState: todoState = {
todos: []
}
export const todoReducer = createReducer(
initialState,
on(createTodo, (todoState, {content}) => ({
todos: [...todoState.todos, {id: Date.now().toString(), content: content}]
}))
)
此时,我想验证是否可以将待办事项添加到 NgRx 存储中。我的 add-todo 组件文件看起来像这样。
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs'
import { Todo } from '../models/todo.model';
import { createTodo, deleteTodo } from '../state/todo/todo.actions';
@Component({
selector: 'app-add-todo',
templateUrl: './add-todo.component.html',
styleUrls: ['./add-todo.component.css']
})
export class AddTodoComponent {
allTodos$ : Observable<Todo[]>;
todo:string = '';
constructor(private store: Store<{allTodos: Todo[]}>){
this.allTodos$ = store.select('allTodos');
}
addTodo(){
this.store.dispatch(createTodo({content:this.todo}));
this.todo = '';
}
}
我可以通过使用 chrome 浏览器的角度开发工具扩展来验证它是否有效。这是我添加 2 个待办事项后截取的屏幕截图。
到目前为止一切顺利。现在我想订阅该值并在添加新待办事项时更新我的待办事项列表组件。但这就是我遇到问题的地方。
首先,我正在创建一个 app.state.ts 文件。我认为这是一种很好的做法,因为我可以将状态的所有不同部分添加到该文件中,并让每个组件导入其中的特定部分。该文件看起来像这样。
import { todoState } from "./todo/todo.reducers";
export interface AppState {
todos: todoState;
}
然后我正在创建我的 todo.selector.ts 文件
import { createSelector } from "@ngrx/store";
import { AppState } from "../app.state";
import { todoState } from "./todo.reducers";
export const selectTodos = (state: AppState) => state.todos;
export const SelectAllTodos = createSelector(
selectTodos,
(state: todoState) => state.todos
)
接下来我要在我的 app.module.ts 文件中注册我的减速器
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { StoreModule } from '@ngrx/store';
import { TodoListComponent } from './todo-list/todo-list.component';
import { AddTodoComponent } from './add-todo/add-todo.component';
import { todoReducer } from './state/todo/todo.reducers';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
TodoListComponent,
AddTodoComponent
],
imports: [
BrowserModule,
StoreModule.forRoot({todos: todoReducer}, {}),
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
最后我在待办事项列表组件中创建了一个 allTodos$ 属性,然后我可以使用它来更新模板中的无序列表。这是我的终端告诉我错误的地方。
import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { SelectAllTodos } from '../state/todo/todo.selector';
@Component({
selector: 'app-todo-list',
templateUrl: './todo-list.component.html',
styleUrls: ['./todo-list.component.css']
})
export class TodoListComponent {
public allTodos$ = this.store.select(SelectAllTodos);
constructor(private store: Store){
}
}
具体来说,这条线。
public allTodos$ = this.store.select(SelectAllTodos);我得到的完整错误是:
错误:src/app/todo-list/todo-list.component.ts:12:40 - 错误 TS2769: 没有过载匹配此调用。重载 1 of 9, '(mapFn: (state: object) => Todo[]): Observable任何帮助将不胜感激。这个错误让我挠头。', 给出了以下错误。 “MemoizedSelector
12 public allTodos$ = this.store.select(SelectAllTodos); ~~~~~~~~~~~~~~Todo[]>”类型的参数不可分配给类型的参数 '(state: object) => Todo[]'。 参数类型“state”和“state”不兼容。 “{}”类型中缺少属性“todos”,但在“AppState”类型中是必需的。重载 2 of 9, '(key: never): Observable', 给出 以下错误。 “MemoizedSelector Todo[]>”类型的参数不可分配给类型的参数 “从不”。 src/app/state/app.state.ts:4:5 4个待办事项:todoState; ~~~~~ 'todos' 在这里声明。
更新 我创建了一个 stackblitz 以便于调试。
ngOnInit
?
export class TodoListComponent implement OnInit {
public allTodos$:Observable<Todo[]>
constructor(private store: Store){
}
ngOnInit(){
this.allTodos$ = this.store.select(SelectAllTodos);
}
}
编辑,你的AppState
有点奇怪。你定义为:
export interface AppState {
todos: todoState;
}
相当于:
export interface AppState {
todos: {
todos:Todo[]
}
}
所以最后,我想你应该替换:
export const SelectAllTodos = createSelector(
selectTodos,
(state: todoState) => state.todos
)
by
export const selectTodos = (state: todoState) => state.todos;
export const SelectAllTodos = createSelector(
selectTodos,
(state: Todo[]) => state
)
编辑 2:如果您更改此代码,就可以了
constructor(private store: Store<{ todos: Todo[] }>) {
this.allTodos$ = store.select('todos');
}