懒功能模块架构迁移到NGRX:Angular 8

时间:2019-08-12 10:01:49

标签: angular ngrx

大家好,我目前正在一个实现了Lazy功能模块体系结构的应用程序中工作。 在下面,您可以看到项目的结构。

enter image description here

由于应用程序不断增长,我们决定将其迁移到Ngrx。

对于我来说,这是一种新模式,我正在寻找迁移指南,但是从头开始创建项目时我只能找到ngrx指南。

能否请您给我一些提示,准则,我应该在哪里小心,以及一些步骤摘要?

谢谢。

2 个答案:

答案 0 :(得分:2)

  

准则

可以延迟加载商店,但这给我带来的问题多于收益。例如,基于路由器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
  

我应该在哪里小心

确保您的减速器返回未修改状态的未定义操作。您可以对此进行测试。没有理由不测试您的减速器。这些是纯函数,易于测试。

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)
  

步骤摘要

与链接几乎相同,但顺序不同:

根存储

  1. 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]
      }
    )

  1. RootStoreModule导入app.module.ts

功能商店

  1. 定义您的功能状态
  2. 定义功能动作
  3. 编写功能效果
  4. 编写您的Feature Reducer(如果可能,请先测试)
  5. 编写您的功能模块
  6. 写下您的index.ts,添加到根index.ts
  7. 将要素状态添加到根状态
  8. 将功能模块声明为Root Store模块的一部分。
  9. 定义特征选择器
  10. 定义任何根选择器(混合功能选择器)

Stackblitz

答案 1 :(得分:0)

因此,在遵循上述指南和一些其他信息之后,我最终对过渡有了半认识,以便对如何使重构遵循此过程有一个完整的了解。

https://www.udemy.com/ngrx-course/

在此过程中,基本上有一个角度懒惰特征体系结构,然后将其重构为使用NGRX。