Taking Nativescript Apps to the NGRX Level
If you have been building Nativescript apps using Angular for a while now. You might have come across NgRx Store by now, but if are still new to the topic, like me this tutorial could help you get started quickly. One thing to know about NgRx is that it requires an initial set up that may delay the app development at first. In order to determine if your app could benefit from this pattern, you may want to take a moment to think on the complexity of the app and its scalability.
For your convenience, I already set up a Nativescript demo app which we will discuss in details on a minute. But first, to download or clone the project go to the project repo at GitHub.
You can find the Repo here.
Now let’s continue…
NgRx/Store is a RxJS state management library for Angular inspired by Redux. In order to implement NgRx, you will need to understand these concepts: Store, Reducer, Selector, and Effects. Since this is a very simple example we are only going to implement a Store, a Reducer, and some Selector.
More information here.
In order to use NgRx on Nativescript or really any Angular Application you will need to install at least the following library:
Although we won’t use them here you may also need to install the other libraries such as:
If you are curious and want to see what other libraries you can use with NgRx you may refer to the previous link or here. You may also find more information about each library in there.
From the diagram, we can see how NGRX Pattern should work.
Let’s try to put that in words:
- The Component has events which we will refer to as Actions
- The Component dispatch an Action and passed to the Reducer
- The Reducer takes the Action and then depending on the state it will return either a copy of the new state or the original state
- The Reducer sents the new state to the Store
- The component then subscribes to the store and finally get’s the new value.
But what’s a Reducer?
A Reducer is a pure function that takes a state and an action as it’s parameters. If you don’t know what a pure function is its basically a function that given the same parameters will return the exact result.
For this tutorial, I’ve put together a very simple app. It simply has a switch that toggles a label on and off. When learning NgRx one of the most difficult parts for me was understanding how it works since all the tutorial I saw got complicated really fast. Therefore I put this demo so you can grab the concepts easily and grow from there.
That’s enough Talk! Let’s see some code
First, let take a look at our project structure so you can identify the files and folders we are going to discuss.
- actions folder – Here we save our item.actions.ts.
- reducers – Here we save our item.reducer.ts.
- states – Here we save our item.state.ts.
There are others structures you can apply, but I particularly like this one because it’s easier to find the particular file you’re looking for. Something to keep in mind is that you should follow the same structure for each feature on your app.
Now let’s have our first look at the Reducer:
Notice that as we mentioned before our reducer takes a state and an action as it’s parameters. Then we use a SWITCH/CASE to get the proper state given an action. For this example, we have two states: default for when our app initialize and TOGGLE_ITEM_LABEL for when we dispatch our action. Also, notice the following line on our TOGGLE_ITEM_LABEL state:
What’s so important about this line?
Another important concept in Redux is immutability. Thus, we can’t access directly the property in the store, but what we do it’s we return a copy of the new state along with the payload.
If you don’t know what does immutability means you can find more information here.
When we are going to use NgRx on our app we will need to import the StoreModule from @ngrx/store into our app.module.ts.
Now let’s take a closer look at the following line:
Since we are implementing lazy loading in our app we need to also add StoreModule import in our items.module.ts.
Now let’s take a look at that:
Notice that on this file we are doing things a little bit different:
Let’s break this down:
- forFeature – used on each feature module.
- items – the name used to reference the reducer we invoking.
- itemReducer – the reducer for the feature.
Now let’s take a moment to make our life easier.
At this point, we could start using our reducer and call it a day, but we would be missing one important piece of the puzzle. Now, you might be wondering what that might be? Well… Strong Typing. Of course, our app doesn’t need strong typing to work, but when we are following Redux pattern we need to remember that we are human beings and we can have typos, errors, or misspelled something. Also since NgRx it’s more suitable for complex applications we could also find ourselves going back and forth to find the Action we need. With strong typing, we ensure that Typescript will let us know if we have any error and also help us with the Types.
In order to have strong typing, one of the things that we need is to define our states:
Since we are only toggling a label our state it’s extremely simple, but on a complex application, you’re surely required to have more.
We’ve been talking about them for a while, but let’s see how we define our actions to help us with strong typing:
Those are quite a few lines of code, but let’s go see them in details:
First, we need to import Action from @ngrx/store
Then we define our ActionTypes as enum so we can define a set of constant. For this scenario, we only need one, but if later on, we needed to add more actions we would define them here along with their classes and actions. We defined this types so that our reducer can determine the state of the app. Also, notice that previously in our reducer we were only managing the state by using “TOGGLE_ITEM_LABEL” as the case, but now we are going to be using our types.
In here export a class with the same name we used for the ActionTypes and we also need to implement the Action interface that we imported from @ngrx/store. Then we need to add a read-only type with the same ActionType we defined above. And then since we are returning a value we defined a constructor with the value type (On this example a boolean value).
In here we are defining our Actions Type. Please keep in mind that this are not to be confused with ItemActionTypes
Now that we can use strong typing let’s take a look at the reducer:
At this point, you should have an idea of I implemented strong typing. But there are some new lines as well. Let’s go through them
First, we imported two methods from @ngrx/store: createFeatureSelector and createSelector
Then we defined a constant called getItemFeature that used createFeatureSelector. If you are wondering what’s that, don’t worry. What it does is that it get’s the name we assigned to the reducer in our feature module (item.module.ts) as a string. Then it uses that string to look up the state from the base object. Now, we can use getItemFeature to give us back the corresponding state of our ItemState.
And lastly, we have another constant called getShowLabel that used createSelector and also implement Function Composition by adding getItemFeature inside of it. Now let’s discuss what’s going on here:
First, we passed getItemFeature so we can start looking for our app state. By doing this we also get access to the property inside the object three which is showLabel. And that’s it! We can finally use NGRX in our component.
Our component’s really basic, but it makes use of NgRx. Let’s see how we do that:
First, we have our imports:
These are the imports we need to use ngrx on our component. All of them, but Store and Select that comes from @ngrx/store library are the classes and actions we discussed above. Also, notice that we have itemActions and fromItems you could also import manually all the classes you need, but if you have many classes this approach makes more sense.
Then we have a boolean property that we will use to update the state of the label.
In order to use the store, we need to do dependency injection and give it the ItemState as it’s type.
Now let’s take a look at our ngOnInit:
In here we are subscribing to our store to get the showLabel property value when the component initialize. We use the keyword Select and give it the selector we defined in our reducer. This selector will then give us the property that holds the value we need. Also since the selector, it’s responsible for getting the state object of our ItemState we will get the value directly when we subscribe. Otherwise, you would have to move through the object tree to get the value you need.
Lastly, we have an onSwitchChecked method that listens to each time we toggle the switch on and off. Each time the switch it’s toggle we will dispatch action using the store dispatch which will take the ToggleItemLabel class with the updated switch state as it’s parameter. Finally updating the value of the showLabel property.
In this tutorial, we discussed how to implement Ngrx on a Nativescript Application . Of course, there’s a lot more to it, but hopefully, this will get you started and give you an idea of how you can use NgRx with Nativescript. I know there’s a lot of examples of how to implement NgRx on Angular applications, but a handful of tutorials for Nativescript and some of them are outdated or won’t work anymore (At least that was my experience). Then you have to go around looking for solutions on a topic you are just getting started. Also, I know that NgRx it’s a hard subject and takes time to digest if you are new to it like me, but I encourage you to not give up and also take a moment to read the Angular examples, watch some tutorials, some courses, etc… The point is don’t give up.