如何检测Angular中@Input()值何时发生变化?

本文探讨如何在Angular应用中检测@Input属性值的变化,包括使用ngOnChanges生命周期钩子和输入属性设置器。当数据是原始类型时,Angular会自动检测变化,但如果是复杂类型,可能需要自定义检测或使用ChangeDetectorRef。示例代码和场景分析帮助理解最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文翻译自:How to detect when an @Input() value changes in Angular?

I have a parent component ( CategoryComponent ), a child component ( videoListComponent ) and an ApiService. 我有一个父组件( CategoryComponent ),一个子组件( videoListComponent )和一个ApiService。

I have most of this working fine ie each component can access the json api and get its relevant data via observables. 我有大部分工作正常,即每个组件可以访问json api并通过observable获取其相关数据。

Currently video list component just gets all videos, I would like to filter this to just videos in a particular category, I achieved this by passing the categoryId to the child via @Input() . 目前视频列表组件只获取所有视频,我想将其过滤为特定类别中的视频,我通过@Input()将categoryId传递给子项来实现这一点。

CategoryComponent.html CategoryComponent.html

<video-list *ngIf="category" [categoryId]="category.id"></video-list>

This works and when the parent CategoryComponent category changes then the categoryId value gets passed through via @Input() but I then need to detect this in VideoListComponent and re-request the videos array via APIService (with the new categoryId). 这有效,当父CategoryComponent类改变时,categoryId值通过@Input()传递,但我需要在VideoListComponent中检测到这一点,并通过APIService(使用新的categoryId)重新请求视频数组。

In AngularJS I would have done a $watch on the variable. 在AngularJS中,我会对变量进行$watch What is the best way to handle this? 处理这个问题的最佳方法是什么?


#1楼

参考:https://stackoom.com/question/2bqI0/如何检测Angular中-Input-值何时发生变化


#2楼

Use the ngOnChanges() lifecycle method in your component. 在组件中使用ngOnChanges()生命周期方法。

ngOnChanges is called right after the data-bound properties have been checked and before view and content children are checked if at least one of them has changed. 在检查数据绑定属性之后以及在检查视图和内容子项(如果其中至少有一个已更改)之前立即调用ngOnChanges。

Here are the Docs . 这是Docs


#3楼

I was getting errors in the console as well as the compiler and IDE when using the SimpleChanges type in the function signature. 在函数签名中使用SimpleChanges类型时,我在控制台以及编译器和IDE中遇到错误。 To prevent the errors, use the any keyword in the signature instead. 要防止出现错误,请改为使用签名中的any关键字。

ngOnChanges(changes: any) {
    console.log(changes.myInput.currentValue);
}

EDIT: 编辑:

As Jon pointed out below, you can use the SimpleChanges signature when using bracket notation rather than dot notation. 正如Jon在下面指出的那样,当使用括号表示法而不是点符号时,可以使用SimpleChanges签名。

ngOnChanges(changes: SimpleChanges) {
    console.log(changes['myInput'].currentValue);
}

#4楼

Actually, there are two ways of detecting and acting up on when an input changes in the child component in angular2+ : 实际上,有两种方法可以在angular2 +中的子组件中输入更改时检测并执行:

  1. You can use the ngOnChanges() lifecycle method as also mentioned in older answers: 您可以使用ngOnChanges()生命周期方法,如旧答案中所述:
    @Input() categoryId: string;

    ngOnChanges(changes: SimpleChanges) {

        this.doSomething(changes.categoryId.currentValue);
        // You can also use categoryId.previousValue and 
        // categoryId.firstChange for comparing old and new values

    }

Documentation Links: ngOnChanges, SimpleChanges, SimpleChange 文档链接: ngOnChanges, SimpleChanges, SimpleChange
Demo Example: Look at this plunker 演示示例:看看这个plunker

  1. Alternately, you can also use an input property setter as follows: 或者,您也可以使用输入属性设置器 ,如下所示:
    private _categoryId: string;

    @Input() set categoryId(value: string) {

       this._categoryId = value;
       this.doSomething(this._categoryId);

    }

    get categoryId(): string {

        return this._categoryId;

    }

Documentation Link: Look here . 文档链接:请看这里

Demo Example: Look at this plunker . 演示示例:看看这个plunker

WHICH APPROACH SHOULD YOU USE? 您应该使用哪种方法?

If your component has several inputs, then, if you use ngOnChanges(), you will get all changes for all the inputs at once within ngOnChanges(). 如果您的组件有多个输入,那么,如果您使用ngOnChanges(),您将在ngOnChanges()中一次性获得所有输入的所有更改。 Using this approach, you can also compare current and previous values of the input that has changed and take actions accordingly. 使用此方法,您还可以比较已更改的输入的当前值和先前值,并相应地执行操作。

However, if you want to do something when only a particular single input changes (and you don't care about the other inputs), then it might be simpler to use an input property setter. 但是,如果您只想在特定的单个输入发生更改时执行某些操作(并且您不关心其他输入),那么使用输入属性设置器可能会更简单。 However, this approach does not provide a built in way to compare previous and current values of the changed input (which you can do easily with the ngOnChanges lifecycle method). 但是,此方法不提供内置方法来比较已更改输入的先前值和当前值(您可以使用ngOnChanges生命周期方法轻松完成)。

EDIT 2017-07-25: ANGULAR CHANGE DETECTION MAY STILL NOT FIRE UNDER SOME CIRCUMSTANCES 编辑2017-07-25:角度变化检测可能在某些情况下仍然不会发生火灾

Normally, change detection for both setter and ngOnChanges will fire whenever the parent component changes the data it passes to the child, provided that the data is a JS primitive datatype(string, number, boolean) . 通常,只要父组件更改传递给子节点的数据,就会触发setter和ngOnChanges的更改检测, 前提是数据是JS原始数据类型(字符串,数字,布尔值) However, in the following scenarios, it will not fire and you have to take extra actions in order to make it work. 但是,在以下情况下,它不会触发,您必须采取额外的操作才能使其工作。

  1. If you are using a nested object or array (instead of a JS primitive data type) to pass data from Parent to Child, change detection (using either setter or ngchanges) might not fire, as also mentioned in the answer by user: muetzerich. 如果您使用嵌套对象或数组(而不是JS原始数据类型)将数据从Parent传递给Child,则更改检测(使用setter或ngchanges)可能不会触发,如用户的答案中所述:muetzerich。 For solutions look here . 有关解决方案,请查看

  2. If you are mutating data outside of the angular context (ie, externally), then angular will not know of the changes. 如果您正在改变角度上下文之外的数据(即外部),则angular将不知道更改。 You may have to use ChangeDetectorRef or NgZone in your component for making angular aware of external changes and thereby triggering change detection. 您可能必须在组件中使用ChangeDetectorRef或NgZone来进行角度感知外部更改,从而触发更改检测。 Refer to this . 参考这个


#5楼

I just want to add that there is another Lifecycle hook called DoCheck that is useful if the @Input value is not a primitive value. 我只想补充说,如果@Input值不是原始值,还有另一个名为DoCheck Lifecycle钩子很有用。

I have an Array as an Input so this does not fire the OnChanges event when the content changes (because the checking that Angular does is 'simple' and not deep so the Array is still an Array, even though the content on the Array has changed). 我有一个数组作为Input所以当内容发生变化时,这不会触发OnChanges事件(因为Angular的检查是'简单'而不是深,所以Array仍然是一个数组,即使数组上的内容已更改)。

I then implement some custom checking code to decide if I want to update my view with the changed Array. 然后,我实现了一些自定义检查代码,以决定是否要使用更改的Array更新我的视图。


#6楼

You can also , have an observable which triggers on changes in the parent component(CategoryComponent) and do what you want to do in the subscribtion in the child component. 您还可以使用一个observable触发父组件(CategoryComponent)中的更改,并在子组件的订阅中执行您想要执行的操作。 ( videoListComponent) (videoListComponent)

service.ts 
public categoryChange$ : ReplaySubject<any> = new ReplaySubject(1);

-----------------
CategoryComponent.ts
public onCategoryChange(): void {
  service.categoryChange$.next();
}

-----------------
videoListComponent.ts
public ngOnInit(): void {
  service.categoryChange$.subscribe(() => {
   // do your logic
});
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值