One of the main advantages of NgRx is facilitating the components communication. The question is in the following case, what is the best option to share data:
<div *ngIf=" content$ | async as content">
<h1>{{content.prop1}}</h1>
<app-component2></app-component2>
</div>
In this case shall we use @input
to send content
down to the app-component2
or it is better in inject the store in the component2
and use the async
pipe again?
CodePudding user response:
There are several approaches to this. One interesting thing to do is have a "viewModel" selector. What this means essentially, is that you have two components, one is the presenter and the other a container. The container selects exactly one selector (you combine everything you need for the specific component into one selector using createSelector
) named say viewModel$
or vm$
. You can also add some side effects to it using the tap
operator in the component if needs be, but usually not. Then you pass it to the async
pipe, take it as a local variable in the template and pass it onto one or more child components via inputs. In such a way, the parent component only handles communications with the store (selecting data and dispatching actions), and others render the data. The template looks something like this:
<div *ngIf="vm$ | async as vm" >
<app-search-filters [filters]="vm.filters"></app-search-filters>
<app-search-result [results]="vm.results"></app-search-result>
<app-save-search
[selectedFilters]="vm.filters"
[savedSearches]="vm.savedSearches"></app-save-search>
</div>
This is a normal approach, but it of course depends on the component's logic and size. If you have a huge page that contains several components that are really loaded with logic and little interconnection, it might be wiser to inject stores into those components and maybe use the "viewModel" approach in those. For example, consider the YouTube video page. Imagine writing it using NgRx. You have several blocks, like the video itself, comment section, suggested videos, and so on. All of those blocks have lots of logic specific only to them, and each might have big chunks of our store related to them. So in such a case, having them broken up into several "smart" components each using the "viewModel" approach might be better. In simpler scenarios, just have one container and one (maybe several) presenter components.
And anyway, do not inject the Store
(or any service for that matter) into components that are mainly meant for rendering the UI.
CodePudding user response:
If you want the <app-component2></app-component2>
to be somewhat generic and be able to pass other data to it in the future I'd say that input is what you want. I also think that it falls somewhat under the DRY principle to inject the store in both parent and child and selecting the same piece of state.