angular - 惰性功能模块架构迁移到 NGRX:Angular 8
问题描述
嘿伙计们,目前我正在一个应用程序中工作,实现了延迟功能模块架构。您可以在下面看到项目的结构。
由于应用程序不断增长,我们决定将其迁移到 Ngrx。
对我来说这是一种新模式,我正在寻找迁移指南,但我只能在从头开始创建项目时找到 ngrx 指南。
您能否给我一些提示、指导方针、我应该在哪里小心,以及可能的一些步骤摘要?
谢谢。
解决方案
指导方针
可以延迟加载您的商店,但这给我带来的问题多于好处。例如,根据路由器 url 和加载的项目实体获取一个选定的项目,该项目实体混合了两个特征存储。以下文章为我提供了一种拆分存储的好方法,同时允许应用程序的任何部分访问存储数据:
https://itnext.io/ngrx-best-practices-for-enterprise-angular-applications-6f00bcdf36d7
对于后代,应用程序结构如下所示:
├── app
│ ├── app-routing.module.ts
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── components
│ ├── containers
│ │ └── my-feature
│ │ ├── my-feature.component.css
│ │ ├── my-feature.component.html
│ │ └── my-feature.component.ts
│ ├── models
│ │ ├── index.ts
│ │ └── my-model.ts
│ │ └── user.ts
│ ├── root-store
│ │ ├── index.ts
│ │ ├── root-store.module.ts
│ │ ├── selectors.ts
│ │ ├── state.ts
│ │ └── my-feature-store
│ │ | ├── actions.ts
│ │ | ├── effects.ts
│ │ | ├── index.ts
│ │ | ├── reducer.ts
│ │ | ├── selectors.ts
│ │ | ├── state.ts
│ │ | └── my-feature-store.module.ts
│ │ └── my-other-feature-store
│ │ ├── actions.ts
│ │ ├── effects.ts
│ │ ├── index.ts
│ │ ├── reducer.ts
│ │ ├── selectors.ts
│ │ ├── state.ts
│ │ └── my-other-feature-store.module.ts
│ └── services
│ └── data.service.ts
├── assets
├── browserslist
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
├── test.ts
├── tsconfig.app.json
├── tsconfig.spec.json
└── tslint.json
我应该在哪里小心
确保你的 reducer 返回未定义操作的未修改状态。您可以对此进行测试。没有理由不测试你的减速器。这些是纯函数,易于测试。
import * as fromProjects from './project.reducer'
import * as fromProjectState from './project.state'
describe('ProjectReducer', () => {
describe('undefined action', () => {
it('should return the default state', () => {
const { initialState } = fromProjectState
const action = {} as any
const state = fromProjects.reducer(initialState, action)
expect(state).toBe(initialState)
})
})
})
花时间确保您的操作类型正确 - 错误很难调试。由于样板文件,您可能会在此处复制并粘贴大量代码。再次,这可以被测试。
describe('LoadProjectsFail', () => {
it('should create an action', () => {
const payload = { message: 'Load Error ' }
const action = new fromProjects.LoadProjectsFail(payload)
expect({ ...action }).toEqual({
type: fromProjects.LOAD_PROJECTS_FAIL,
payload,
})
})
})
遵守 NgRx 文档 - 有一些更改,教程通常至少落后一个版本。例如
this.store.pipe(select(projectSelectors.getProjectsLoading))
// versus
this.store.select(projectSelectors.getProjectsLoading)
步骤总结
与链接几乎相同,但顺序不同:
根存储
- 写
root-store.module.ts
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools'
import { environment } from 'src/environments/environment'
// import { MyFeatureStoreModule } from './my-feature-store/';
// import { MyOtherFeatureStoreModule } from './my-other-feature-store/';
@NgModule({
imports: [
CommonModule,
// MyFeatureStoreModule,
// MyOtherFeatureStoreModule,
StoreModule.forRoot({}),
EffectsModule.forRoot([])
// Store devtools
!environment.production
? StoreDevtoolsModule.instrument({
name: 'My App',
})
: [],
],
declarations: []
})
export class RootStoreModule {}
添加以下文件,这些文件开始时几乎是空的:
index.ts
import { RootStoreModule } from './root-store.module'
import * as RootStoreState from './state'
import * as RootStoreSelectors from './selectors'
//export * from './employee'
//export * from './project'
//export * from './router'
export { RootStoreState, RootStoreSelectors, RootStoreModule }
state.ts
import { routerState } from './router'
import { employeeState } from './employee'
import { projectState } from './project'
export interface State {
router: routerState.State
employees: employeeState.State
projects: projectState.State
}
selectors.ts
import { createSelector } from '@ngrx/store'
import { Project } from './project/project.model'
import { routerSelectors } from './router'
import { projectSelectors } from './project'
export const getSelectedProject = createSelector(
projectSelectors.getProjectsEntities,
routerSelectors.getRouterState,
(entities, router): Project => {
return router.state && entities[router.state.params.id]
}
)
- 导入
RootStoreModule
到app.module.ts
特色商店
- 定义您的功能状态
- 定义特征动作
- 写出你的特征效果
- 编写你的特征缩减器(如果可能,首先测试)
- 编写您的功能模块
- 写你的
index.ts
,添加到rootindex.ts
- 将特征状态添加到根状态
- 将功能模块声明为根存储模块的一部分。
- 定义特征选择器
- 定义任何根选择器(混合特征选择器)
堆栈闪电战
推荐阅读
- go - goavro 无法使用模式验证 json 数据
- python - 来自用 Python 自动化无聊的东西的“逗号代码”程序
- ios - 提前从 HTML 加载 WKWebView 页面
- python - 使用 numpy 从两个对象向量生成对矩阵
- javascript - NestJs - 如何在拦截器上获取请求正文
- javascript - 调用 $('#idname').html(""); 后 jQuery 表单提交不起作用
- go - 如何在recover() 中捕获runtime.errorString?
- javascript - 自定义文件输入按钮不会选择文件
- android - 传递给第二个 Activity 的 ArrayList 数据未在 TableLayout 中显示
- python - 如何在 Python 3 的 exec 命令中停止执行?