如何在Angular 2中从Service异步传递数据至Component
解决Angular异步数据传递问题:正确传递bikeImgs数组
你遇到的核心问题是异步操作的时机不匹配:Service里的HTTP请求是异步完成的,而你的组件在ngOnInit里直接取itemService.bikeImgs时,请求还没返回数据,所以拿到的是空数组。
下面是两种推荐的解决方案,你可以根据使用场景选择:
方案一:用BehaviorSubject共享数据(适合多组件共享同一批数据)
这种方式会在Service里保存数据的最新状态,所有订阅的组件都能获取到最新数据,且只会发起一次HTTP请求,适合需要跨组件共享数据的场景。
修改ItemService代码:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() export class ItemService { // 用BehaviorSubject保存数组状态,初始值设为空数组 private bikeImgsSubject = new BehaviorSubject<string[]>([]); // 对外暴露Observable,避免外部直接修改内部数据 public bikeImgs$: Observable<string[]> = this.bikeImgsSubject.asObservable(); constructor(private http: HttpClient) { this.http.get("https://api.unsplash.com/collections/iuAONw1hf3k/photos/?query=''&per_page=20&client_id=wjJ9ECR9hrNPSx6HMZADgO7D0lWw_kXHPHfyyMMxy2Y&page=1") .pipe( // 直接把返回数据映射成我们需要的URL数组 map((data: any[]) => data.map(e => e.urls.small)) ) .subscribe(imgs => { // 请求成功后更新Subject的值,通知所有订阅者 this.bikeImgsSubject.next(imgs); }); } }
修改组件代码:
import { Component, OnInit } from '@angular/core'; import { ItemService } from './item.service'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { bikeImgs: string[] = []; constructor(private itemService: ItemService) { } ngOnInit() { // 订阅Observable,等数据返回后再执行赋值和打印 this.itemService.bikeImgs$.subscribe(imgs => { this.bikeImgs = imgs; console.log("here " + this.bikeImgs); }); } }
方案二:Service提供获取数据的方法(适合单组件使用或按需请求)
如果不需要多组件共享数据,也可以让Service提供一个返回Observable的方法,组件调用后订阅获取数据,这种方式更灵活,适合按需发起请求的场景。
修改ItemService代码:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() export class ItemService { constructor(private http: HttpClient) { } // 定义方法返回Observable,让组件自己决定何时订阅 getBikeImgs(): Observable<string[]> { return this.http.get("https://api.unsplash.com/collections/iuAONw1hf3k/photos/?query=''&per_page=20&client_id=wjJ9ECR9hrNPSx6HMZADgO7D0lWw_kXHPHfyyMMxy2Y&page=1") .pipe( map((data: any[]) => data.map(e => e.urls.small)) ); } }
修改组件代码:
import { Component, OnInit } from '@angular/core'; import { ItemService } from './item.service'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { bikeImgs: string[] = []; constructor(private itemService: ItemService) { } ngOnInit() { // 调用Service方法并订阅,拿到数据后再处理 this.itemService.getBikeImgs().subscribe(imgs => { this.bikeImgs = imgs; console.log("here " + this.bikeImgs); }); } }
为什么原来的代码不行?
HTTP请求是异步操作,subscribe里的代码只会在请求成功后才执行。你的组件在ngOnInit里直接赋值this.bikeImgs = this.itemService.bikeImgs时,subscribe里的push操作还没执行,所以拿到的是初始的空数组。
通过Observable订阅的方式,我们能确保只有当异步数据返回后,才会执行赋值和打印操作,这样就能正确获取到bikeImgs数组了。
内容的提问来源于stack exchange,提问作者A7x
相关产品推荐
相关产品推荐

