While we can throw our entire application into a single
AppComponent, that's not ideal, and it's certainly not good architecture. One way to categorize your directives is to think about "state". When we refer to "state" we are referring to the different states in which our application can be, based on either user interactions or based on the URL or link in which the user arrived to our application. Components can be divided into those that know about or change state, and those that do not.
Stateful components are "aware" of the state of the application, and can also change or mutate the state of the application. These component are often routed to, but not always. We can refer to these components as "stateful", or "smart".
On the other hand, our application is often composed of many modular directives and components that are not "aware" of the state of the application. In other words, it doesn't matter what the URL is, or what interactions the user has taken; these components are considered "stateless" or "dumb". Components that fit into this category know how to receive data, present the data or user interface, and when necessary, notify the parent component that something has happened.
Benefits of Stateful vs Stateless Components
There are several benefits to separating components into these two categories: stateful and stateless components. Some of these benefits include:
- Modular architecture
- Reusable stateless components
- Single responsibility
By separating components into either stateful vs stateless we can design and architect our application to be more modular. Our application is sliced into small units of code. And, these small units of code can be delegated out to multiple people in a team or within an organization. This is a big win, especially for enterprises and organizations that need to increase the velocity of development by parallelizing the tasks and user stories.
Reusable Stateless Components
One of the primary benefits of implementing an architecture that separates components into stateful vs stateless is that the stateless components are highly reusable. And, with this comes reduced maintenance and costs, and increased velocity and ease of testability. If we can create components that are indeed stateless, then that means that the component can be reused in any situtation, no matter the state of our application.
In the video we looked at the
PeopleListComponent, which accepted an array of
People objects. This component is stateless, or "dumb" if you will, because the component knows how to do one thing: list people. It doesn't matter if the people are being listed in an administrator section of our application, or if the people are going to be listed in another part of our application. It simply knows how to do one thing: list people. And, that's it. The component accepts an array of
People objects via an
@Input() binding and displays the people.
Also in the video we saw that the
PeopleListComponent uses another stateless
PersonDetailsComponent. This "stateless", or "dumb" component knows how to do one thing: display the details of a
Person. The component accepts a single
Person object and displays the details of the person; including: the person's gender, skin color, hair color, height, eye color, mass, and birth year.
Both of these component, the
PeopleListComponent and the
PeopleDetailsComponent are highly reusable because they are stateless. Given the input data they are deterministic in nature. Similar to a pure function, given the same input, stateless functions will always produce the same output.
Stateless componenes have a single responsibility. When given the input, or none at all, they always deterministically produce the exact same output. This follows the best practices of Angular for creating components that have single responsibility. As discussed previously, this enables us to reuse these components throughout our application because we know exactly how the will behave and respond given the data that we provide.
This last point is very important, especially to organizations that depend on the reliability of their applications. When using the "container" and "presenter", or "stateful" and "stateless" component design and architecture, we often create components that are highly modular and reusable. And, as a resule, these component are easy to test. This is a huge win. In part because developers are often less inclined to write unit or end-to-end tests, but also because writing tests for module and stateless components are easier and simpler to write. This often leads to increase testability of our components. Automated testing leads to applications that are hardened, reliable, and dependable.