如何在父组件和子组件之间共享不断变化的数组?

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 检测策略的工作方式是,对于像 arrayobject 这样的复杂数据类型,它不检查里面的内容,它只检查这些数据的身份数据类型。

这意味着如果你想在你的 @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 的更改检测。它不会检测数组内部的变化,只会检测整个引用的变化。每次发生更改时,您都必须创建一个全新的数组并将其分配给传递给子组件的变量。