ViewChild vs Input/Ouput - Angular Best Practices

2020-07-13 08:03发布

问题:

It seems to me that in almost all cases where we specify component @Inputs/@Outputs we could alternatively not have any @Inputs/@Outputs but instead use @ViewChild to access component properties directly. For example, consider these two possible APIs for a pager:

Option 1: Expose current page and total pages as @Inputs, make event emitters (@Outputs) for the next/previous page requests.

<pager 
    [currentPage]="..." 
    [totalPages]="..." 
    (requestsNextPage$)="..." 
    (requestsPreviousPage$)="..."
></pager>

Option 2: Make simple properties for current page and total pages, make observables/subjects for next/previous page requests and expose via @ViewChild.

<pager></pager>

@ViewChild(PagerComponent)
pager: PagerComponent

pager.currentPage = ...
pager.totalPages = ...

pager.requestsNextPage$.subscribe(...)
pager.requestsPreviousPage$.subscribe(...)

My question is, if both of these options are equally possible in most cases, what is the preferred/best practice and why?

回答1:

The two situations you describe are not equivalent.

Situation A:

<child [property]="value"></child>

The child component will be rendered with "property = value" and whenever "value" changes, the child component's view will be updated (because an input property changed).

Situation B:

<child></child>

child.property = value;

The child component is rendered with "property = value" (depending when in the lifecycle this code runs) and further changes will NOT be reflected in the child component's view.


If you're just setting an initial value that never changes, then it may be possible for these two situations to be equivalent. However, that's unlikely to be what you want to do. Angular is very aggressive about re-using components, and one of the criteria it uses is the @Input properties. I have run into trouble where a component was reused instead of deleted and re-created due to this behavior, and it can be very frustrating to understand and debug.



回答2:

When you are using @Input(), for every change the ngOnChanges() will be called which may causes more noise.

Using ViewChild() Property decorator that configures a view query. The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated.

So ViewChild() will not create such noise and is the prefer way over @Input()