Angular 2 Application Architecture – Building Redux-like apps using RxJs.
The difficulty of handling state in single page applications
Probably not all single page applications have a huge state management problem. Imagine a easy CRUD app used to administer hint data for security privileges.
For that type of single page function probably using Angular 2 Forms and/or NgModel
if you so adopt is an approach that will yield good conclusions with low complexity involved.
But there are use crate where this approach is known to fall short. The most common example is the acclaimed unread messages counter issue in Facebook, that lead to the formation of the Flux architecture (see here the original talk).
When is a Flux-like architecture needed ?
As one of the core representative of React (Pete Hunt – @floydophone) says in the React How-To, you probably don’t need Flux! When you want it, you will know when you use it. If you have a use container like the following, you probably need Flux:
- multiple parts of your app exhibit differently the same data. For example an outlook app displays a information on a list and updates folder respond of unread messages
- some data can be together edited by both the user using the UI or events coming from the backend via server push
- you have a need for undo/redo of at least part of the application state
These use cases are actually not that occasional, depending on the type of app.
An architecture for complex UIs
Think of the Netflix UI, where a movie potentially arrive in multiple lists. If you add a movie to your favorites and scroll down and see that movie again in another list, you want to see it marked as a favorite already. Again, the same data shows up in various parts of the UI and an action obligation to affect the whole UI always – this is a typical use case for Flux.
Is Flux/Redux the only solution for use cases like this?
There are other options too besides the single atom of state option given in the rest of this post. You can for example like house the application around the impression of observable data services. Thats possibly just another version of Flux.
But let’s assume you fall upon one of these grip in a part of your app: How can we build a Redux-like single atom of state application in Angular 2?
Building a Flux Angular 2 app using RxJs
As in other Flux access, it all starts with the UI Actions. The user interacts with the page and UI Actions. The user interacts with the page and as a result multiple parts of the app want to respond to that communication.
Application Actions
An action is a message that defines what happened in the UI: A Todo was added, removed, toggled. To make this type safe, lets create a class for each action:
And then lets define a Typescript union category that is a union of all the action types defined:
As we can see, the Actions are just POJOs that transit the data necessary for the different parts of the application to adapt themselves.
But how can an Action be dispatched to different parts of the application that need it?
Using the Action Dispatcher
An action is dispatched via the action courier. This gets implant in any place of the application that needs to haste actions, typically Smart or Controller-like components like the TodoList in the sample function:
You might be awestruck what the dispatcher
name inside the @Inject
annotation is, this is just a token name for analyze a specific injectable, more on this later. The important thing to to know now is that the courier can be used to dispatch any action to the rest of the function:
As we will see later, the envoey was built in a few lines of RxJs. But before seeing how its built internally, let’s see how other parts of the function can react to an action.
Defining the application state
Let’s start by defining what the operation state looks like:
As we can see, the application state subsist of a list of agitation items which is the data of the operation, plus an instance ofUiState
. Let’s take a look at UiState
:
UiState
contains any state in the UI other than the data, such as for example what is the message directly being displayed to the user, and a flag indicating if some action is ongoing in the backend.
Introducing the Application State Observable
Now that we know what the state of the function looks like, we need to imagine a tide which consists of the different states that the function has over time: the application state observable.
As new actions are triggered, this stream will give off new values that mirror the result of those actions: todos get added, toggled, deleted, etc. What we consider into is this:
We will see next how we can build such an observable, it will only catcha couple of lines of RxJs. For now, let’s conclude that the utilization state observable already exists, and that it can be implant anywhere in the application:
This means that any part of the function that wants to react to new state can have an apparent injected and subscribe to it. That part of the application does not know what action prompt the arrival of the new state: it just notice that new state has appear and that the view should be amend to reflect it.
How to use the application state observable
We can subscribe to the application state apparent like to any other apparent. Let’s say that we want to gate the list of todos and pass it to the template. We could advocate to the observable and populate a todos list represantive variable:
This would be one to do it, but Angular 2 foresees a better way.
Consuming observables using the async pipe
Another way to consume observables is to use the Angular 2 async
pipe. This pipe will subscribe to the observable and return its last result:
Here we can see that the list of todos show from a todos
observable. This observable is defined via a getter method in a controller class and is derived from the application state observable using the map
operator:
As we can see its simple to build a Flux app once the courier and the application state observable are available:
- inject the dispatcher anywhere an action needs to be prompt inject the application state anywhere in the opertaion that needs to revert to a new application state
Let’s now see how these two constructs can be built using RxJs.
Building an Action Dispatcher
The dispatcher is actually just a traditional event bus: we want to use it to prompt events, and want some part of the function to be able to subscribe to the behavior that it emits.
To utensil this, the esiest way is to use an RxJs Subject, that appliance both the Observable and the Observer interfaces. This means we can not only ante up to a Subject, but use it to emit code as well.
Making the dispatcher injectable
The dispatcher to be injected anypalce on the application needs an injection name. Let’s start by creating such name using an OpaqueToken
:
This token can then be used to registry a Subject in the Angular 2 dependency injection system. Lets add this line to the boostrap statement of the application:
This means that whenever the dependency injection arrangement gets asked for object named dispatcher
, this Subject will get injected.
Avoiding event soup while using the dispatcher
even if the dispatcher is a Subject, its better to mark its type upon injection as an Observer only:
This is being we really only want the dispatcher to be used in function code to dispatch events, such as for example:
We want to avoid most operatioin code to accidentally subscribe directly to the dispatcher, instead of subscribing to the utilization state.
There potency be valid use bin to subscribe directly to the envoy but most of the time this is acceptable not intended. With the dispatcher defined, let’s see how can we determine the application state observable.
Building an application state observable using RxJs
First let’s define an original state for the application, again using an needle name of initialState
:
This means that at any time the name initialState
is desired for injection, the object defined above is give in: it have an empty list of todos and some initial non-data UI state.
Defining the application state
The application state percepciable can be built as follows:
The application state is a a action of both the initial state and the current of actions that occur over time:
- the first value of the state apparent is the initial state itself
- then the first action appear and the initial state is convert accordingly and the state observable emits the new state
- the next action is prompt, a new state is emitted
Calculating the new application state
Each new state is the result of administer the new action to the earlier state, which looks a lot like a practicalreduce
operation. The first step to calculate the new application state is then to decide a series of reduction functions, Redux style. Here we have the reducer function for all todo-revelant actions:
This is a typical reducing function: pandemic a state and an action, count the next state of the todo list. A idenrtical reducing function
calculateUiState
can be construct for the UiState
part of the operation state (see here).
Using reducers to produce a new application state stream
Now that we have the reducer functions, we need to define a new perceptible stream that takes the conduct stream and the initial state, and goods a new state.
Its time to use the driver, thescan
operator. This operator catch a stream and creates a new current that afford the output of a reduce function over time.
What we are doing here is catching the current state of the operation, starting with the initial state, and then constantly calculate the new state as a conclusion of the previous case and the action itself.
The amount of scan
is also an appreciable whose values are the any states of the operation over time.
And that’s it! As the Redux docs themselves mention, an different to Redux is a few lines of RxJs! But there are closed a couple of loose ends we will look into.
Avoiding reducer functions from being called multiple times for one action
While debugging an function built like this, you will attention that if you add different application state buyer (like multiple async
pipes), the reducer functions will be hit multiple times, one for each subscriber.
Although there is nobody fundamentally wrong with that, for the sake of candor of debugging you perhaps want to insure that the reducer functions are only bring out once per action dispatched, like in Redux.
For this we introduce the second RxJs operator we will use, the share operator (see here for more on that):
There is another loose end, which is how to use the function state apperciable in an application association scenario.
Ensuring that the application state observable can be consumed at application startup
You might want to add the function state apparent and use it in city in your application where your whole app is not totally setup yet.
For example, at application association time, like here. This will not work the way you expect, because its possible that not all donor are wired at the point the first application state value arrival.
The explanation for this is to cause the function state observable a current that when subscribed always arrival the last value, even if it was spew in the past before the subscription took place.
For this, we need to wrap the plain state apparent into a
BehaviourSubject
:
This will ensure that subscribers will always accept at least the basic state value.
How should pure components use dispatcher and state
Pure factor can receive observables as input current, but they should not have the dispatcher or case observable insert into them, as this would pickle them to this particular application, making them not recyclable.
If a pure basic wants to dispatch an action, it rather issues an event via EventEmitter
, and its the good component that will ante up to the event emitted it and in response dispatch an action.
Comparison of building Angular 2 apps with Redux
Let’s keep in mind that we will before need to know RxJs to use Angular 2, because Observables are part of the Angular 2 API for stuff like Forms or Http.
And as per the docs of Redux itself, the same approch as Redux can be resolve in RxJs using the scan driver and a couple of operators more, as we have just saw. Also RxJs is before shipped with Angular 2.
So it would seem to make impression when coming across use capsule that require Flux to appliance them in RxJs instead of Redux, if by anything else by a matter of using a library we already have to know how in any case. Using a Redux implementation made in RxJs like ngrx is a good way to go too.
In the end the solid approach around Redux are more large than the library itself.
Alternatives
Another available alternative to separate atom of state function is to build an application around the notion of observable data services.
Conclusions
Its still early for the Angular 2 community to know what will a typical Angular 2 application look like, and how state will be handled.
With all these benefit, its easy to baggy sight of thing important. There are for sure ways to do Flux-like apps in Angular 2, but the main question is do we really need a Flux-like architecture for our entire application?
See more:
Programming virgin with Javascript
15 New JavaScript Libraries for Developers
The post Angular 2 Application Architecture appeared first on I'm Programmer.