In this post we are going to understand:
- What is state
- What is state in a web application
- Categories of state
- different ways to manage state
- Libraries to manage angular application state
So, Unlike classic web applications, single page applications have an application state – and this must be managed to avoid inconsistencies and data binding cycles. That’s why developers of single page applications have to deal with state management.
What is application state?
Have a look at the image below, how many item in this image can be considered as state?
Answer is everything you see in this image can be considered as an state of a web application. from our web page's button color to our webservice response data, everything can be considered as an state of our application and you might want to take care of these state.
Categories of states in web application:
- Server state - Data resides at server or database which belongs to client application is called as server state
- Persistent state - When client makes a call to server and server responds with some state(data) that is called persistent state
- URL/Router state - Any information resides in URL is called as URL/Router state
- Client State - current client application state, after all manipulations from URL state, for e.g applying some filter based on an url parameter
- Transient State - current client application state, after all manipulations that are not represented by url parameters
- Local UI state - State of UI components like button color
In the real time applications, you might come across to scenario where you will have web service fetching some list of items and you are providing filter option to filter those items based on some condition at client side.
So in this example two states mentioned in the blue border are really important to be taken care, because they are in two different domains so they should always be synchronized. other two states, "Client manipulation" and "UI component" states are also important but they are really easy to manage so we will not discuss about these states.
How to manage state in a web application:
Now we need some place to store our application data at a place from where all components can access that data, to achieve this here are some suggestions:
Some old school Suggestions:
- Save everything in the URL
- Save everything in the cookies
- Sessions and local storage
- Hidden fields
- Keep it stateless, don't care about state
Yes above mentioned suggestions are correct and can be used to implement state management, but some problems will come along if we use these methods, for example - most of the data in URL are in plain text and there is an limitation of size etc. that is why these methods should not be considered to manage state.
- Smart and dumb components
- Observable data services
- State manage libraries
Smart and dumb components:
In this concept, while designing the web application we can categorize our components into smart and dumb components where smart component has business logics and knows about application states and also knows how to manage states.
on the other hand dumb components will not have any business logic and will not have idea about states.
If you design your application using this concept you will have your component structure like this
Here bookList and bookItem components contain business logic and are stateful hence they are smart component and "like-Button" and "shopping cart" are dumb ones.
To implement something like this we have to use @Inputs and @Output decorators as shown below:
And done ! but wait... with only three components the code looks so ugly and unmanagable, imagine if you have a very complex application.
- Just parent child interation between components
- Not ideal for complex applications
- Unreadable code
Observable data services:
In this concept we will have one separate service which will be responsible to manage data and state of components.
This implementation will require rxjs library's observables and subjects.
Now you can inject this service to your components and emit values to this subject and all the components which are subscribed to this subject will get the value and gets their state updated.
also we can subscribe to router's params change to manage router state.
that's it, all done...so this means rxjs is providing us everything that we need to manage our application state right?
After implementing above steps your application structure will look like this:
but wait.. there is a scenario :(
What if you have multiple shared services? then your application structure will look like this:
Now that becomes really complicated to manage.. right?
Now if you have application structure like this then you probably will seek some other better alternative to achieve state management.
And that is where external state management libraries comes into the picture.
NgRx - an popular state management solution for angular ecosystem based on redux
when to consider this library in your angular application for state management:
- Shared - if you have states shared over multiple shared services in your application
- Hydrated - if your state keeps hydrated from any of the source like localstorage
- Available - if your state is so available like you have your state in routes
- Retrieved - if your state is retrieved with a side effects like API data calling
- Impacted - if your state is impacted by other states
Now NgRx is based on few principle of Redux mentioned below:
- Single source of truth - One objectory that can be serializable and it can also be hydrated
- Read only - State can only be manipulated only via reducers
- Pure function - All the reducers we will use to manipulate state will be pure functions
Now let's see this implementation in a picture:
So as mentioned in the picture, we have our state from where we can query part of state and show it to our component.
Now if we want to change something in the state we will dispatch an action.
Actions will be received by reducers which are nothing but pure functions to produce new state and send it back to the original state.
Benefits of having state management over traditional application without state management
- Allow us to minimise the number of http requests done to server
- Allow us to easily have parts of view reflect new versions of data
- Allow us have much improved user experience with minimal loading indicators
Long journey so far... so in my next post i am going to explain how to actually implement selectors, actions and reducers in an angular application using NgRx.