首页 > 解决方案 > 子组件中的可观察输入为空。为什么?

问题描述

我面临着一个我不明白的情况。我有一个父组件(示例中为 app.component),它从 API 获取其数据作为可观察对象

然后使用异步管道将此数据传递给子节点(hello.component)。

然后那个孩子接收输入,但是当 ngOnInit 在孩子中运行时,输入是null.

我不明白为什么,也不知道如何使输入成为 API 的实际返回值。对detectChanges()in app.component 的调用是触发子项更改检测的绝望尝试,但这不会重新运行 ngOnInit,所以它有点没有实际意义。我把它留在那里是因为这就是我正在使用的实际代码的样子。

我知道这段代码很糟糕。我没有写它。不幸的是,我正在使用的组件就是这样,我无法重构它,因为你猜对了,没有单元测试。我正在努力清理它,但现在我必须按原样重用该组件。

Stackblitz:https ://stackblitz.com/edit/angular-ivy-rw1xte?devtoolsheight=33&file=src/app/hello.component.ts

// app.component.ts
import { ChangeDetectorRef, Component, VERSION } from "@angular/core";
import { interval, Observable, of } from "rxjs";
import { mapTo, tap } from "rxjs/operators";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  public name$: Observable<any> = of({});

  constructor(private cdRef: ChangeDetectorRef) {}

  public ngOnInit() {
    this.name$ = interval(3000).pipe(
      mapTo(() => {
        first: "Eunice";
      }),
      tap(() => this.cdRef.detectChanges())
    );
  }
}
<!-- app.component.html -->
<hello [name]="name$ | async"></hello>
<p>
  Start editing to see some magic happen :)
</p>
// hello.component.ts
import { Component, Input } from "@angular/core";

@Component({
  selector: "hello",
  template: `
    <div *ngIf="name">
      <h1>Hello {{ this.name.first }}!</h1>
      <h1>{{ greetings }}</h1>
    </div>
  `,
  styles: [
    `
      h1 {
        font-family: Lato;
      }
    `
  ]
})
export class HelloComponent {
  @Input() name: { first?: string }
  public greetings: string = "";
  public firstName: string = "";

  public async ngOnInit() {
    console.log('name:',this.name); // name: null

    if (this.name) {
      // this conditional is always false because this.name is always null
      // and so this never runs.
      console.log("got name");
      this.firstName = this.name.first || "fallback";
      this.greetings = await new Promise(resolve =>
        resolve("how do you do, ${firstName}?")
      );
    }
  }
}

标签: javascriptangularrxjs

解决方案


this.name$ = interval(3000).pipe(
    mapTo({
        first: "Eunice"
    }),
    tap(() => this.cdRef.detectChanges())
);

请像上面那样修复它。mapTo不需要接受函数。它没有为你犯错误吗?:)

此外,安装组件时name输入是null正确的hello。您需要签入名称,或者仅在名称可用时才ngOnChanges需要安装组件。hello

例如:

<hello *ngIf="name$ | async as name" [name]="name"></hello>

或者

public async ngOnChanges() {
    console.log('name:', this.name); // name: null

    if (this.name) {
        ...
    }
}

推荐阅读