【问题标题】:Cannot read property 'subscribe' of undefined angular无法读取未定义角度的属性“订阅”
【发布时间】:2018-10-04 07:44:49
【问题描述】:

我有一个服务UserService,它有一个方法getUsers(),这个服务在不同的角度组件之间共享。

该方法调用 API 并返回数据。我想保存最后一次 API 调用的结果/状态,所以我使用BehaviorSubject 来保存最后一个状态,这样如果不同的组件调用getUsers(),应该只有一个 API 调用,否则必须返回保持状态。

这就是我的实现方式

private _users$: BehaviorSubject<User[]>;

constructor(private http: HttpClient) {
    this._users$ = new BehaviorSubject([]);
}

getUsers(): BehaviorSubject<User[]> {
    if (!this._getUsersState().length) {
        this._loadUsers();
        this._users$.subscribe(() => {
            return this._users$;
        });
    } else {
        return this._users$;
    }
}

_loadUsers() {
    let _users$ = this.http.get(`${this._context}/users/`);
    _users$.subscribe((users: User[]) => {
        this._users$.next(Object.assign([], users));
    });
}

_getUsersState(): User[] {
    return this._users$.getValue();
}

在组件中

this.userService.getUsers().subscribe((users: any) => {
    console.log(users);
});

但我收到以下错误

ERROR TypeError: Cannot read property 'subscribe' of undefined

我猜如果长度为 0,get users 会自动返回。

我该如何解决这个问题?这种方法好吗?

【问题讨论】:

  • 你能检查一下this._users$.subscribe是在_loadUser解析observable结果之前还是之后调用的吗?对我来说,问题是您在 _loadUsers 上的 subscribe 函数完成其工作之前执行该函数
  • 谢谢,但错误来自组件,即使在 _loadUser 之前调用该方法,它也会返回 BehaviourSubject 所以没有错误。

标签: angular rxjs observable behaviorsubject


【解决方案1】:

像这样编辑您的服务:

private _users$ = new BehaviorSubject<User[]>(null);
public usersChanged = this._users$.asObservable();

constructor(private http: HttpClient) {
}

getUsers(): BehaviorSubject<User[]> {
    if (!this._getUsersState().length) {
        this._loadUsers();
        this._users$.subscribe(() => {
            return this._users$;
        });
    } else {
        return this._users$;
    }
}

_loadUsers() {
    let _users$ = this.http.get(`${this._context}/users/`);
    _users$.subscribe((users: User[]) => {
        this._users$.next(Object.assign([], users));
    });
}

_getUsersState(): User[] {
    return this._users$.getValue();
}

像这样编辑你的组件逻辑:

this.userService.usersChanged
.subscribe((users: any) => {
  if(!!users){
    console.log(users);
  } else {
    console.log("No user found!");
  }
});

最好有一个变量是private 行为主体的可观察变量。所以你只需订阅它,只要它的状态发生变化,它就会发出。

【讨论】:

  • 可能是这样,但在服务中也会有其他方法,所以组件会调用类似服务的 addUser、getUsers,这种模式呢?
【解决方案2】:

getUsers 方法应该返回一个 observable,在服务中订阅 observable 不是一个好习惯。 如果要维护用户状态,请使用单例服务。像这样声明服务中的属性:

public users: Users[] = [];


private getUsers(): Observable<Users[]> {
 if (!this.users.length) {
   return this.http.get(`${this._context}/users/`);
 }
 return Observable.of(this.users);
}

在你的组件中

this.userService.getUsers().subscribe((users: User[]) => {
    this.userService.users = users; // (or users.slice(0)
    console.log(users);
});

【讨论】:

  • 服务是提供数据的,为什么组件会提供通过服务本身返回的数据?
  • 你的观点并不完全正确。我刚刚创建了一个商店服务。这也是 redux 的工作方式。但是您永远不应该订阅您的服务,因为您将无法取消订阅。如果您不取消订阅,则会出现内存泄漏。
猜你喜欢
  • 1970-01-01
  • 2021-11-23
  • 2019-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-22
  • 2020-03-07
  • 1970-01-01
相关资源
最近更新 更多