如何在父组件和子组件之间共享不断变化的数组?
How can I share a constantly changing array between Parent and Child Component?
我有两个组件,一个父组件和一个子组件。在父组件中,我有一个空数组,开头为:
publicCrowsOnPerchValues: number[] = [];
我使用此数组在使用 chart.js
的图表上显示数据。我正在使用 Firebase 的 RTDB 来存储和检索数据。以下是上述数组在 父组件 :
中的填充方式
getCrowOnPerchDataChildren() {
//get a snapshot of the child added
this.$childCrowOnPerchSub = this.crowboxService
.getCrowOnPerchData()
.stateChanges();
this.$childCrowOnPerchSub
.subscribe(action => {
//set the showUserId to false as the user has already set up the crowbox
this.showUserId = false;
//get the index of the key from the date array
let indexOfKey = this.crowsOnPerchDate.indexOf(action.key);
//if the index is -1, then the date does not currently exist
//this means that it is a new date, so we push it onto the array
//since it is a new date, we also push on the value onto the value
//array
if (indexOfKey == -1) {
this.crowsOnPerchDate.push(action.key);
this.crownsOnPerchValues.push(action.payload.val().value);
} else {
//if it does exist, then we don't need to add the new date
//simply replace the existing data value with the new data value
//for the same date
this.crownsOnPerchValues[indexOfKey] = action.payload.val().value;
}
//reset the bar charts data as well as labels
this.crowOnPerchChartLabels = this.crowsOnPerchDate;
this.crowOnPerchChartData = [
{ data: this.crownsOnPerchValues, label: "Number Of Crows That Landed On The Perch" }
];
});
}
在上面的函数中,我实际上是在用户向 Firebase RTDB 中添加数据时填充数组。它通过订阅 observable 来工作。
现在,我想将这个数组传递给我的子组件。
在 子组件 中,我设置了一个 Input()
变量,如下所示:
@Input() crowsOnPerch!:number[];
然后,在 parent.component.html 中,我像这样传递数组:
<app-child [crowsOnPerch]="crownsOnPerchValues"></app-child>
这有效,除了,我收到空数组。我怎样才能在更新时不断接收数组?我应该改用共享服务吗?
Angular 检测策略的工作方式是,对于像 array
或 object
这样的复杂数据类型,它不检查里面的内容,它只检查这些数据的身份数据类型。
这意味着如果你想在你的 @Input
中反映出变化,你不应该改变现有的数组,而是创建一个新的数组(这样你的数组的身份就会改变)。
您可以使用展开运算符来做到这一点:
// Instead of this:
this.crownsOnPerchValues.push(action.payload.val().value);
// Do this:
this.crownsOnPerchValues = [
...this.crownsOnPerchValues,
action.payload.val().value
]
// Instead of this:
this.crownsOnPerchValues[indexOfKey] = action.payload.val().value;
// Do this:
this.crownsOnPerchValues[indexOfKey] = action.payload.val().value;
this.crownsOnPerchValues = [...this.crownsOnPerchValues];
实现它的“反应式”方法是使您的数组成为一个 Observable 流,然后连接子组件以将其作为输入接收。它应该看起来像这样,
父组件
*.ts
public myArray$: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);
当您的数组更改时,将更改推送到 Observable 流
this.myArray$.next([1, 2, 3]);
*.html
<child-component [myArrayInput]="myArray$ | async">
子组件
*.ts
@Input() myArray: number[];
我正在使用 BehaviorSubject 来允许使用 .next() 函数,但您也可以使用简单的 Observable 来做到这一点。
它没有按照您的方式工作的原因是 Angular 的更改检测。它不会检测数组内部的变化,只会检测整个引用的变化。每次发生更改时,您都必须创建一个全新的数组并将其分配给传递给子组件的变量。
我有两个组件,一个父组件和一个子组件。在父组件中,我有一个空数组,开头为:
publicCrowsOnPerchValues: number[] = [];
我使用此数组在使用 chart.js
的图表上显示数据。我正在使用 Firebase 的 RTDB 来存储和检索数据。以下是上述数组在 父组件 :
getCrowOnPerchDataChildren() {
//get a snapshot of the child added
this.$childCrowOnPerchSub = this.crowboxService
.getCrowOnPerchData()
.stateChanges();
this.$childCrowOnPerchSub
.subscribe(action => {
//set the showUserId to false as the user has already set up the crowbox
this.showUserId = false;
//get the index of the key from the date array
let indexOfKey = this.crowsOnPerchDate.indexOf(action.key);
//if the index is -1, then the date does not currently exist
//this means that it is a new date, so we push it onto the array
//since it is a new date, we also push on the value onto the value
//array
if (indexOfKey == -1) {
this.crowsOnPerchDate.push(action.key);
this.crownsOnPerchValues.push(action.payload.val().value);
} else {
//if it does exist, then we don't need to add the new date
//simply replace the existing data value with the new data value
//for the same date
this.crownsOnPerchValues[indexOfKey] = action.payload.val().value;
}
//reset the bar charts data as well as labels
this.crowOnPerchChartLabels = this.crowsOnPerchDate;
this.crowOnPerchChartData = [
{ data: this.crownsOnPerchValues, label: "Number Of Crows That Landed On The Perch" }
];
});
}
在上面的函数中,我实际上是在用户向 Firebase RTDB 中添加数据时填充数组。它通过订阅 observable 来工作。
现在,我想将这个数组传递给我的子组件。
在 子组件 中,我设置了一个 Input()
变量,如下所示:
@Input() crowsOnPerch!:number[];
然后,在 parent.component.html 中,我像这样传递数组:
<app-child [crowsOnPerch]="crownsOnPerchValues"></app-child>
这有效,除了,我收到空数组。我怎样才能在更新时不断接收数组?我应该改用共享服务吗?
Angular 检测策略的工作方式是,对于像 array
或 object
这样的复杂数据类型,它不检查里面的内容,它只检查这些数据的身份数据类型。
这意味着如果你想在你的 @Input
中反映出变化,你不应该改变现有的数组,而是创建一个新的数组(这样你的数组的身份就会改变)。
您可以使用展开运算符来做到这一点:
// Instead of this:
this.crownsOnPerchValues.push(action.payload.val().value);
// Do this:
this.crownsOnPerchValues = [
...this.crownsOnPerchValues,
action.payload.val().value
]
// Instead of this:
this.crownsOnPerchValues[indexOfKey] = action.payload.val().value;
// Do this:
this.crownsOnPerchValues[indexOfKey] = action.payload.val().value;
this.crownsOnPerchValues = [...this.crownsOnPerchValues];
实现它的“反应式”方法是使您的数组成为一个 Observable 流,然后连接子组件以将其作为输入接收。它应该看起来像这样,
父组件
*.ts
public myArray$: BehaviorSubject<number[]> = new BehaviorSubject<number[]>([]);
当您的数组更改时,将更改推送到 Observable 流
this.myArray$.next([1, 2, 3]);
*.html
<child-component [myArrayInput]="myArray$ | async">
子组件
*.ts
@Input() myArray: number[];
我正在使用 BehaviorSubject 来允许使用 .next() 函数,但您也可以使用简单的 Observable 来做到这一点。
它没有按照您的方式工作的原因是 Angular 的更改检测。它不会检测数组内部的变化,只会检测整个引用的变化。每次发生更改时,您都必须创建一个全新的数组并将其分配给传递给子组件的变量。