问题
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
- 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]
}
)
- Import
RootStoreModule
intoapp.module.ts
Feature Store
- Define your Feature State
- Define Feature Actions
- Write your Feature Effects
- Write your Feature Reducer (Test first if possible)
- Write your Feature Module
- Write your
index.ts
, add to rootindex.ts
- Add Feature State to Root State
- Declare Feature Module as part of Root Store module.
- Define Feature Selectors
- 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