@Component({

selector: 'movies',

template: `

<div>

<div *ngFor="let movie of movies">

<div>

{{movies.name}}

Year: {{movie.year}}

Gross: {{movie.gross}}

</div>

</div>

</div>

`

})

export class Movies {

private movies: Array<any>

constructor(private movieService: MovieService) {}

ngOnInit() {

this.movieService.getMovies().subscribe(data => this.movies = data)

}

}

The app actually stems from the root component AppComponent. Now we broke the app into components, and in each component, we decide the view of the app it will handle: the HeaderComponent handles the display of the header, the PageNameComponent deals with the display of the current page position. MoviesComponent handles the fetching and display of the movies.

One thing we have to note is that the Components have a single responsibility, it deals with a particular thing. Also, Components are built to be re-used. With a single responsibility comes re-usability. If you see your self re-writing a similar Components know that its time to isolate the Component so you can plug it anywhere you want its functionality, in that way we write better components.

Looking at the above Components we would think that they are all re-usable, but if we look closer we will see they have different concerns especially the MoviesComponent .

To write better components in Angular, we should follow the below steps:

Identify Mixed concerns

Divide Components into Container and Presentational

Try as much as possible to reduce your Container Components

Identify Mixed concerns

Mixed concerns are when your components have different responsibilities. A Component may be responsible for:

State management

UI presentation

Business logic

Data fetching

User interaction

Those are different concerns, Components should be responsible for one of the above. Looking at the MoviesComponent :

@Component({

selector: 'movies',

template: `

<div>

<div *ngFor="let movie of movies">

<div>

{{movies.name}}

Year: {{movie.year}}

Gross: {{movie.gross}}

</div>

</div>

</div>

`

})

export class MoviesComponent {

private movies: Array<any>

constructor(private movieService: MovieService) {} ngOnInit() {

this.movieService.getMovies().subscribe(data => this.movies = data.movies)

}

}

This Component is responsible for these:

UI presentation: It displays the array of movies

Business logic: It is tied to the business logic of the application, the app has its logic on how to get movies.

Data fetching: It fetches its data from a Service.

State management: It injects a Service MoviesService and queries the movies array from server and slices the data from the returned Observable.

See we have identified different concerns in our Component.

Mixed Components

What are Mixed Components? Mixed Components are Components that span multiple concerns. They contain at least two concerns listed above.

The MoviesComponent is a mixed component, it has multiple concerns: It presents the UI of the fetched movies, it injects the MovieService, closely tied to the business logic. Whenever a mixed component gets large we have to divide the component into Container components and Presentational Component.

Divide Components into Container and Presentational

It’s always a good practice to divide a component into Container component and Presentational component. Why should we divide a component into Container and Presentational? It is majorly because of reusability, maintainability, and optimization.

Reusability: This is the reason why SPAs are componentized, to make reusing of a group of views possible. Imagine re-writing certain views regularly. It will be ideal to pack the view in a component and call it wherever you need it.

Millions of libraries are made up of reusable components. Look at the Angular Material library, it is made up:

Buttons

Tabs

Tables

Labels

Modals

etc

All those are components made to be re-usable, we often need button in different places in our app. We know that button have different styles:

The Button component is crafted like this:

@Component({

slector: 'button',

template: `

<button class=""></button>

`

})

export class Button {

@Input() }

Look the Button component does not inject any Service, does not side-effect, it receives data to render via the input bindings and content projection ng-content .

These re-usable components are what is shared with the outside world. These components are shared via NPM or Bit.

Maintainability: Even as the system contains many parts, each of the parts addresses a single concern each of them is easy to maintain. There will be no breaking changes if one part decides to change.

Optimization: If a component becomes predictable, we can guess the values and optimize based on that info. Presentational components are much more like pure functions. They work based on the inputs they are given without affecting state outside of their scope, so with this, we know when it would re-render. It would re-render when the inputs changes and since its display is dependent on an outside data, we can safely memoize the component to only re-render when its inputs changes. Having as much as Presentational in our app is good, it will greatly boost the performance rate of our app.

Container Components

These components are also known as “Smart” components. Smart? as in smart? Yes, they are smart enough to produce their own data they render or pass down to child components. They are self-contained, they need not be supplied data via the input/output bindings. They are tied to the business logic of the application, not meant to be reused or shared.

Their template is majorly made up of child components and input/output bindings. Container components generally:

Pass data to Presentational components or react to events from them presentational components.

Inject Services or the Store service if using State management.

Perform the business logic either via Services or Effects when using the Store.

Presentational Components

Like the name implies it displays the UI. They are also called “Dumb” components, aww :(, why dumb? They don’t produce the data they display. They are dependent on a parent component to pass them its data via its input bindings.

They do not know of any Service or inject them, their only responsibility are to present UI element and to delegate user interaction up to the container elements via its event bindings. Presentational components are very good to be re-usable: Buttons, Tabs, etc because they are predictable and doesn’t side-effect.

Try as much as possible to reduce your Container Components

What I am trying to say here? If you have 25 components in your app and Container components are 20, try to reduce it like to 10 or 5. Why? Because they will impact the performance of your app. Container component cannot be optimized because of its unpredictable nature but Presentational components are inputs and outputs dependent so they are predictable in that case we can optimize them using the OnPush Cd strategy.

When making your components as Dumb as possible try

Not to mutate its inputs: Mutation would lead to data inconsistency. If a component mutates the parent data, because Angular uses === equality check to know when to re-render a child component, the child component would not re-render because there is no reference change which is caused by the mutation so there will be an incorrect display of data.

Not to side-effect: Side-effecting adds un-predictability to Presentational components making them hard to optimize. If a component needs to communicate data it should emit it via its output bindings.

Not to inject Service: Injecting any Service makes the component have a more than one concern: Ui presentation and Business logic. Presentational components do not get their own data. If a Presentational component needs data it should get it via its input bindings.

Making our Movies App Components Better

Now, we know how to write better components, let’s refactor our Movies app components. Looking at the MoviesComponent

@Component({

selector: 'movies',

template: `

<div>

<div *ngFor="let movie of movies">

<div>

{{movies.name}}

Year: {{movie.year}}

Gross: {{movie.gross}}

</div>

</div>

</div>

`

})

export class Movies {

private movies: Array<any>

constructor(private movieService: MovieService) {}

ngOnInit() {

this.movieService.getMovies().subscribe(data => this.movies = data)

}

}

We have to split it into Container and Presentational components.

@Component({

selector: 'movies',

template: `

<div>

<movies-list [movies]="movies"></movies-list>

</div>

`

})

export class Movies {

private movies: Array<any>

constructor(private movieService: MovieService) {}

ngOnInit() {

this.movieService.getMovies().subscribe(data => this.movies = data)

}

} @Component({

selector: 'movies-list',

template: `

<div *ngFor="let movie of movies">

<div>

{{movies.name}}

Year: {{movie.year}}

Gross: {{movie.gross}}

</div>

</div>

</div>

`,

changeDetection: ChangeDectionStrategy.OnPush

})

export class MoviesList {

@Input() movies

}

We have split the MoviesComponent, the MoviesList component now handles the UI presentation of the movies array. See the Movies component is no longer concerned about how the movies are rendered, it just passes it to the MoviesList component.

The MoviesList only concern is UI presentation, it receives the movies array from the @Input() movies binding, and uses the *ngFor to loop through the movies array and render them. We optimized the MoviesList component using the OnPush strategy if the movies array changes referentially Angular would re-render the MoviesList component if not it would not re-render the component.

We can further refactor the Movies component to use Effects. Service-based components use Services to get data, these Services may depend on other services, this causes components to have multiple concerns. Using Effects decreases the responsibilities, this is important because it will make our component less stateful. Now, we will put the movie data to Store, then inject Store in our Movies components:

@Component({

selector: 'movies',

template: `

<div>

<movies-list [movies]="movies"></movies-list>

</div>

`

})

export class Movies {

private movies: Observable<Array<any>> = this.store.select(state => state.movies)

constructor(private store: Store) {}

ngOnInit() {

this.store.dispatch({type: 'Load New Movies'})

}

}

Now, the Movies component is no longer concerned about how the movies are gotten, it just tells the Store that it wants to load new movies and selects the movies slice from the state state => state.movies . The responsibility of the loading of movies is up to the Effects.

class MoviesEffects {

loadMovies$ = this.actions.pipe(

ofType('Load New Movies'),

switchMap(action =>

this.moviesService.getMovies()

.map(res => ({ type: 'Load New Movies Success',payload: res }))

.catch(err => Observable.of({ type: 'Load New Movies Failure', payload: err }))

);

) constructor(private moviesService: MoviesService, private actions: Actions) {}

}

Our app has three routes new movies , highest-grossing movies , and trending movies .

new movies lists the newest movies highest-grossing movies list highest grossing movies trending movies lists trending movies

These have one thing in common they list movies, their components would use the MoviesList component to display the movies.

@Component({

selector: 'movies',

template: `

<div>

<movies-list [movies]="movies"></movies-list>

</div>

`

})

export class Movies {

private movies: Array<any>

constructor(private movieService: MovieService) {}

ngOnInit() {

this.movieService.getMovies().subscribe(data => this.movies = data)

}

} @Component({

selector: 'movies-grossing',

template: `

<div>

<movies-list [movies]="movies"></movies-list>

</div>

`

})

export class MoviesHighestGrossing {

private movies: Array<any>

constructor(private movieService: MovieService) {}

ngOnInit() {

this.movieService.getHighestGrossingMovies().subscribe(data => this.movies = data)

}

} @Component({

selector: 'movies-trending',

template: `

<div>

<movies-list [movies]="movies"></movies-list>

</div>

`

})

export class MoviesTrending {

private movies: Array<any>

constructor(private movieService: MovieService) {}

ngOnInit() {

this.movieService.getTrendingMovies().subscribe(data => this.movies = data)

}

}

See we re-used the Presentational component MoviesList components in all the components. There is no need to re-write a display list for each component.

Conclusion

Anything worth doing is worth doing well, in fact very well. Writing better components help us a lot. Whenever we want to test, scale, refactor or optimize, it will be so easy because the components have been prepared for such actions because of how they were structured. Writing better components is like preparing for the worst in the future, we won’t see ourself editing large components.

If you have any question regarding this or anything I should add, correct or remove, feel free to comment, email or DM me.

Thanks !!!

Learn More