Here are all the components patterns I found in the Ember community, that I think is good to know.

Components patterns

Presentational component

Photo by Joshua Hoehne on Unsplash

This is the basic type of component. It used for presenting, formatting data. It takes some properties and displays them in a more meaningful way. It shouldn’t be responsible for data fetching or business logic. One good example can be a component for displaying a user’s avatar.

Example definition:

// user-avatar/template.hbs

<img src={{user.avatarUrl}}>

Call API example:

{{user-avatar user=user}}

References:

https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

https://medium.com/@learnreact/container-components-c0e67432e005

Contextual component

Photo by michael podger on Unsplash

These components can be used as a wrapper eg. for markup. They can act like any other component type. The only difference is that they can pass content inside of the block to a specific place in the component using the {{yield}} statement.

Example definition:

// page-header/template.hbs

<div class="jumbotron">

<h1>Hello, world!</h1>

<p>{{yield}}</p>

</div>

Call API example:

{{#page-header}}

How are you?

{{/page-header}}

References:

https://guides.emberjs.com/release/components/wrapping-content-in-a-component/

Container component

Photo by Guillaume Bolduc on Unsplash

This pattern is used for data manipulation, actions handling and all the business logic around. For example, it can fetch the user and format the content using presentational components. Container component can also act as the contextual component, allowing you to overwrite the content and markup by passing a block.

Example definition:



import Component from '

import { inject as service } from '

import { computed } from ' // user-profile/component.jsimport Component from ' @ember/component ';import { inject as service } from ' @ember/service ';import { computed } from ' @ember/object '; export default Component.extend({

store: service(), id: null,



user: computed('id', function() {

return id ? this.store.findRecord('user', this.id) : null;

}),

}); // user-profile/template.hbs

{{#if hasBlock}}

{{yield user}}

{{else}}

{{user.name}}

{{user-avatar user=user}}

{{/if}}

Call API example:

{{#user-profile id=7 as |user|}}

<h1>{{user.name}}</h1>

{{/user-profile}}

References:

https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

https://medium.com/@learnreact/container-components-c0e67432e005

Composable component (aka Higher-Order Component)

Photo by Rick Mason on Unsplash

Its role is to deliver to you meaningful components/parts from which you can build your business logic and features but also serves as a great extension for container components. They should still stay flexible so you can add your own markup or modify behaviors. This kind of components can be used in a top-level template where you define your application layout but can be also used to form another component.

Example definition:

// articles-list/template.hbs

{{yield (hash

variables=(hash

articles=articles

) components=(hash

list=(component "articles-list/list" articles=articles)

pagination=(component "articles-list/pagination")

)

)}}

Call API example:

{{#articles-list articles=user.articles as |articlesList|}}

{{#articlesList.components.list as |list|}}

{{#list.components.item as |article|}}

<h1>{{article.title}}</h1>

<p class="lead">{{article.body}}</p>

{{/list.components.item}}

{{/articlesList.components.list}} {{articlesList.components.pagination}}

{{/articles-list}

References:

https://www.chriskrycho.com/2018/higher-order-components-in-emberjs.html

https://riptutorial.com/ember-js/example/10416/composable-components

https://www.youtube.com/watch?v=6N4qsO22fmw

More about composable components soon in next articles :)