Lazy Feature Modules architecture migration to NGRX: Angular 8

余生颓废 提交于 2019-12-13 09:28:59

问题


Hey guys currently i am working in an application with Lazy features modules architecture implemented. Below you can see how the project is structured.

Since the application is keep on growing we decided to migrate it to Ngrx.

As is a new pattern for me i am searching for migration guidelines but i can only find ngrx guidelines when creating a project from scratch.

Could you please give me some hints, guidelines,where should i be careful , and possibly some steps summary?

Thanks you.


回答1:


guidelines

It's possible to lazy load your store but this has caused me more issues than benefits. For example getting a selected project based on the router url and loaded project entities which mixes two feature stores. The following article has provided me a nice way to split up the store whilst allow any part of the application access to store data:

https://itnext.io/ngrx-best-practices-for-enterprise-angular-applications-6f00bcdf36d7

For posterity the application structure looks like:

├── 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

where should i be careful

Make sure your reducer returns the state unamended for undefined actions. You can test for this. There's no excuse not to test your reducers. These are pure functions and easy to test.

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)
    })
  })
})

Take the time to ensure your actions types are correct - the errors are hard to debug. Due to boilerpate you'll likely copy and paste alot of code here. Again this can be tested.

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,
    })
  })
})

Keep to the NgRx documentation - there's been a few changes and tutorials are normally at least one version behind. e.g.

this.store.pipe(select(projectSelectors.getProjectsLoading))
// versus
this.store.select(projectSelectors.getProjectsLoading)

steps summary

Pretty much the same as the link but a different order:

Root Store

  1. Write 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 {}

Add the following files which will start of pretty much empty:

  • 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. Import RootStoreModule into app.module.ts

Feature Store

  1. Define your Feature State
  2. Define Feature Actions
  3. Write your Feature Effects
  4. Write your Feature Reducer (Test first if possible)
  5. Write your Feature Module
  6. Write your index.ts, add to root index.ts
  7. Add Feature State to Root State
  8. Declare Feature Module as part of Root Store module.
  9. Define Feature Selectors
  10. Define any Root Selectors (mixes feature selectors)

Stackblitz




回答2:


So after following the guidelines above and some other info i end up having a semi-understanding about the transition , in order to have a complete understanding on how you should make the refactoring follow this course.

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

In the course basically there is angular lazy features architecture which is then refactored to use NGRX.



来源:https://stackoverflow.com/questions/57459138/lazy-feature-modules-architecture-migration-to-ngrx-angular-8

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!