DEV Community

Michael De Abreu
Michael De Abreu

Posted on • Updated on

Why you should consider using classes to declare the state of @ngrx/store

Hi there! Long time no see. I'm been kind of busy setting my blog, I'm sorry. I made the UI from the ground, because I didn't like any of the themes, as a fact, I don't like mine either, but we have to start somewhere. Anyway, here is the post, hope you enjoy it.


originally posted on my blog


Introduction

This week I've been playing around (again) with @ngrx, its store, effects, and go on, trying to integrating to a version of Tour of Heroes. It's been more than a year since the last time I play with it, and I have to say, I'm becoming a more productive developer, and this has also evolve to become a better platform. The fact that observables now use piped operators, makes everything easier to understand.

I been watching some tutorials, and been reading a lot about the changes introduced with recent versions of the store, and I don't know. I change the application state in two days. You may think that is a lot of time, but I didn't know how to use effects, and also I wanted to follow the Angular Style Guide on this one, and the example app of @ngrx does not follow it, and most of the redux examples are made, well, for a React project.

I had my thoughts about the structure of an Angular application, but they were heavily influenced by the structure of React applications. The current Angular Code Style have change my mind about, but this is for another post.

The recommended way

What I want to talk in this post, is about the recommended way to declare a state.

export interface AppState {
    counter: number;
}

export const initialAppState: AppState {
    counter: 3,
}
Enter fullscreen mode Exit fullscreen mode

Why? Ok, here is why. It IS recommended that you use a POJO for declaring the state, and the actions. But, does it really hurt to declare an immutable Typescript class to declare the State?

Classy

export class AppState {
    public readonly counter: number = 3;
}
Enter fullscreen mode Exit fullscreen mode

When this is set in the store configuration, the state initializes as a POJO as well, so there is no side effects going around here.

import { StoreModule } from '@ngrx/store';

export class AppState {
    public readonly counter: number = 3;
}

const reducers = (state = new AppState(), action) => state; // Best reducer ever!


@NgModule({
  imports: [
    StoreModule.forRoot(reducers, {
      initialState: new AppState(),
    })
  ]
})
export class AppStoreModule {}
Enter fullscreen mode Exit fullscreen mode

I think this is clearer. You make sure that you set all the required properties, and only need to call the constructor when ever you need. And, you can use the AppState as a interface, wherever you want.

For AOT

If you would like to use this pattern with Angular AOT, you need to use the spread operator to introduce the new state, cause Angular Compiler needs to analyze all the metadata from the decorators. And you need to use function reducers, instead of a arrow function assignment.

function reducers(state = new AppState(), action) {
 return state; // Still the best reducer ever!
}

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, {
      initialState: { ...new AppState() },
    })
  ]
})
export class AppStoreModule {}
Enter fullscreen mode Exit fullscreen mode

Do you think this is a good thing o a bad thing? Why? I would like to read your comments.

Top comments (2)

Collapse
 
3zsforinsomnia profile image
Zachary Levine

I feel like I am not understanding some of the benefits here. It seems like syntactically it is nearly the same. I can see potential benefits if you wanted to put validation for setting properties in the class as then it is not in the reducer, or more cleanly handling multiple properties changing due to one action. I personally tend to do that either before actions are dispatched or in "conditional" actions themselves, as an alternative mechanism for keeping the reducer itself simple. Not sure how I would combine the two approaches myself, but I can easily see others making use of this pattern.

Thoughts on other benefits or use cases?

Collapse
 
michaeljota profile image
Michael De Abreu

Sorry for the delay answering this. I made another post talking about this, and a style guide proposal. I answer what you are asking here:
ngrx-ducks#interfaces.

This is a personal opinion, but when you see the code, you see the benefits of using this approach.

Thanks you so much for your feedback, and I hope you like the proposal.