In this post we will cover the Feature and Presentation Component Design pattern. This pattern has been called many things such as
- Smart/Dumb Components
- Stateful/Stateless Components
- Container Components
For this post we will use the terminology of Feature and Presentation. This pattern has been covered many times and across other frameworks other than Angular but I would just like to give my perspective of this useful pattern.
What is a Feature or Presentation Component? First lets define what a component is. A component is simply a small encapsulated piece of a user interface. Many frameworks and libraries use components including Angular, React, Ember, and Vue. Components allow us to break a large complex UI into smaller easier to understand pieces. This is similar to the way we break our code up into smaller functions. This makes our UI easier to understand and reuse in our applications.
When building large UI systems with components our application it becomes a tree like structure. Components get used inside of other components. Most of the time these parent child relationships need to communicate back and forth. In Angular components we communicate via Input properties and Output events. Parent components can set a property of a child component and a child component can emit events up to parent components.
This makes it clear where data is flowing from but it brings up a few questions. Who should fetch data from the server? Which component is responsible for saving the data? This is where Feature and Presentation Components come in.
Feature vs Presentation
In our web applications we can take advantage of the Feature and Presentation Component pattern. Lets look at the example app below.
Here we have a product search page. The user can search for products with filters. The search view shows a list of product items.
Lets define the Feature component first. A Feature component is a top level component that contains all other components in our feature. This commonly is a routed component in Angular. Our feature components are responsible for gathering data from various services for our feature to use. If our user saves data the feature component is responsible to pass that data to our Angular Services to save the data to our server API. Feature components are sill very slim with the amount of application logic. We try to defer this logic to Services if possible. For this example the
product-search is our Feature Component and will be composed of many Presentation components.
Where do Presentation Components fit in? As our Search Feature component grows in complexity we can refactor our component into smaller reusable Presentation Components. Presentation Components behave like pure functions taking in the data via
@Input and emitting data via
@Output. This allows the majority of our UI to not know the underlying implementation detail of where the data came from. For example a
product-item component takes in a
@Input of a product to display. This allows the
product-item component to have the only responsibility of rendering a the product when the data is passed to it.
<app-product-item [item]="itemData" (select)="selectProduct($event)"></app-product-item>
product-item could also have a single
@Output to notify the feature component when a user clicks a product in the list. This is useful because we can now use the item component for different situations whether that should display a different view or save some information to our API.
Presentation components do not have to be reusable. Keeping the pure Inputs and Outputs makes it easier to debug features. Because our Feature Component is the only component communicating with Services it is easy to determine where the data is coming from and in turn making it easier to debug.
There are downsides to this though. As the feature grows in complexity we may have a deeply nested component structure. Since component events only bubble up one level at a time we will have to manually pass up to each parent component. Sometime introducing other sub feature or container components can help elevate this. At this point it brings into question how to manage state which can be for another blog post :)
Presentation Components do take more time to create and hook up than just having large single Feature Components but in the long term can help the maintainability and reusability of our components. Many if not most Presentation Components can be abstracted into a style guide or UI library for the project. To get ideas of component design and style guide maintainability I recommend Brad Frost’s fantastic book Atomic Design.