ngrx / platform

Reactive State for Angular
https://ngrx.io
Other
8k stars 1.97k forks source link

PoC: Schematics to create a main feature reducer file #3302

Open moniuch opened 2 years ago

moniuch commented 2 years ago

I would like to ask you to consider providing a schematic which I don't believe exists yet, but which to me seems like the missing bit in the puzzle.

The artifact of the schematic would be a main feature reducer file (say, [name].feature-reducer.ts) holding an empty state interface, and an empty reducer map. This would be the home for the slices to come, this would be the file which you would reference in the feature schematic (ie. the --reducers parameter).

An example of the output would be (let me base on the code from SO):

export interface UserModuleState {}
export interface State extends fromRoot.State {}
export const reducers = {};

export const selectUserModuleState = createFeatureSelector<UserModuleState>('userModule');

This would be a home for the future slices: search, detail, detailBase, which you would add using every time using @ngrx/schematics:feature --reducers user.feature-reducer.ts, and end up with:

export interface UserModuleState {
  search: fromSearch.State;  
  detail: fromUserDetail.State;
  detailBase: fromDetailBase.State;
}

export interface State extends fromRoot.State {
    userModule: UserModuleState;    
}

export const reducers = {    
    search: fromSearch.reducer,
    detail: fromUserDetail.reducer,
    detailBase : fromDetailBase.reducer
};

// ...
// + suitable edits in the declaring module

IMO, there is no schematic available currently that produces this code. Having it available would make the whole store-building flow very intuitive and free from guesswork:

Currently, from what I was able to find out in my experiments, setting up a feature reducer requires manual work and model-defining hassle.

If accepted, I would be willing to submit a PR for this feature

[ ] Yes (Assistance is provided if you need help submitting a pull request) [ ] No

moniuch commented 2 years ago

Just wanted to share with you my PoC results and thus maybe convince this schematic would be helpful:

With the admin.feature-reducer.ts file created manually, containing the following skeleton code,

admin.feature.reducer.ts

import { ActionReducerMap, createFeatureSelector } from "@ngrx/store";
import * as fromRoot from '@myorg/app-config';

export const ADMIN_FEATURE_KEY = 'admin';

export interface State extends fromRoot.State {
  admin: AdminModuleState;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface AdminModuleState {}

export const reducers: ActionReducerMap<AdminModuleState> = {};

export const selectUserModuleState = createFeatureSelector<AdminModuleState>('adminModule');

I ran ng generate @ngrx/schematics:feature --reducers admin.feature-reducer.ts 3x to create 3 slices: and the result is quite pleasing (although still requiring minor touchups)

image 2022-01-26 18-14-54

admin.feature-reducer.ts

import { ActionReducerMap, createFeatureSelector } from "@ngrx/store";
import * as fromRoot from '@myorg/app-config';
import * as fromSlice1 from './slice1/slice1.reducer';
import * as fromSlice2 from './slice2/slice2.reducer';
import * as fromSlice3 from './slice3/slice3.reducer';

export const ADMIN_FEATURE_KEY = 'admin';

export interface State extends fromRoot.State {
  admin: AdminModuleState;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface AdminModuleState {
  [fromSlice1.slice1FeatureKey]: fromSlice1.State;
  [fromSlice2.slice2FeatureKey]: fromSlice2.State;
  [fromSlice3.slice3FeatureKey]: fromSlice3.State;
}

export const reducers: ActionReducerMap<AdminModuleState> = {
  [fromSlice1.slice1FeatureKey]: fromSlice1.reducer,
  [fromSlice2.slice2FeatureKey]: fromSlice2.reducer,
  [fromSlice3.slice3FeatureKey]: fromSlice3.reducer,
};

export const selectUserModuleState = createFeatureSelector<AdminModuleState>(ADMIN_FEATURE_KEY);

I only noticed some minor flaws in the feature schematics, although very easy to fix:

  1. The feature (= slice) reducer is placed in the main State interface, rather than AdminModuleState

feature-reducer-after-g-feature

  1. The declaring module is updated with the slice reducer, although it is not necessary, because it is already included in the module reducer map. The effects though are ok, they need to stay.

declaring-ng-module

A very quick fix. Could be, more surprises will come up as I continue with it. Otherwise the setup looks very good, so I think the feature-reduce schematic is worth consideration. Please let me know what you think.

timdeschryver commented 2 years ago

I think that the reducers schematics do exactly what you're looking for.

npx ng generate @ngrx/schematics:reducer customers --creators=true --group=true --path=src/app/store/reducers --reducers index.ts --api true
moniuch commented 2 years ago

In this command, you are adding the generated reducer to --reducers index.ts so you have this file ready. My ticket is about providing a way to create this sort of index file for a feature module which is expected to contain multiple slices.

This would be the home for the slices to come, this would be the file which you would reference in the feature schematic (ie. the --reducers parameter).

May I know how do create index.ts within a feature module which you know will host multiple slices? Please let me know where I can be clearer, maybe it's bco my English :)

timdeschryver commented 2 years ago

@moniuch Thanks for the clarification, I got confused with the comment because it seemed like you wanted to add reducers to the action reducer map.

I think that an additional schematic isn't required, what do you think if we would re-use the --reducers flag? Currently it only adds the new reducer to the feature, but we could extend it so it can also create the initial state interface and action reducer map.

moniuch commented 2 years ago

@timdeschryver Good we are on the same page now :) I will be glad to see any sort of solution, be it a new schematic or a new flag to the existing schematic that will just create a minimal reducer as in the first snippet. We can refer to it as --minimal or --bare

timdeschryver commented 2 years ago

@moniuch do you want to create a PR for this? To start simple I would not introduce any new flags and create an empty state/reducer where we currently do nothing (https://github.com/ngrx/platform/blob/master/modules/schematics/schematics-core/utility/ngrx-utils.ts#L89). If needed we can add that later.

moniuch commented 2 years ago

@timdeschryver Ekhm... WIth my zero experience in writing schematics this could take a while, but I'm gonna try anyway.

santoshyadavdev commented 2 years ago

Hi @moniuch,

Are you working on it? I can take this if its available.

moniuch commented 2 years ago

Hi @santoshyadavdev

I can take this if its available. Please do. Thank you.

santoshyadavdev commented 2 years ago

@timdeschryver can you assign this to me

tomalaforge commented 1 year ago

@santoshyadavdev are you working on it ? Otherwise I can take this PR

santoshyadavdev commented 1 year ago

You can take this one.

rainerhahnekamp commented 4 months ago

@tomalaforge do you still want to do it? Otherwise, I could take over here

tomalaforge commented 4 months ago

@rainerhahnekamp yes you can take it 👍