强制订阅者从服务中重新请求数据?

时间:2019-12-08 13:30:23

标签: angular typescript rxjs angular-services angular-components

我有一个简单的结构,具有多个组件和单个服务[StackBlitz]:

<code>digraph G {   s[label="Service"];   c0[label="Component0"];   c1[label="Component1"];   c2[label="Component2"];      c0->c1;   c0->c2;   c1->s;   c2->s; }</code>

服务

@Injectable()
export class Service {
  constructor(private http: HttpClient) {}

  post(entity: IEntity): Observable<IEntity> {
    return this.http
               .post<IEntity>('/api/entity', entity)
               .pipe(map(parseDates));
  }

  get(): Observable<IEntity[]> {
    return this.http
               .get<IEntity[]>('/api/entity')
               .pipe(map(parseDates));
  }
}

Component0

@Component({
  selector: 'app-component0',
  template: `<app-component1></app-component1>
             <app-component2></app-component2>`,
  styleUrls: []
})
export class Component0 {}

Component1

@Component({
  selector: 'app-component1-create',
  template: `<button (click)="submit()">Submit</button>`,
  styleUrls: []
})
export class Component1 {    
    constructor(private service: Service) { }

    submit() {
        this.service.post({foo: 'bar'})
                    .subscribe(console.info, console.error)
    }
}

Component2

@Component({
  selector: 'app-component2-table',
  template: `<pre>{{ entities | json }}</pre>`,
  styleUrls: []
})
export class Component2 implements OnInit {
    entities: IEntity[];

    constructor(private service: Service) { }

    ngOnInit() {
        this.service.get()
                    .subscribe(entities => this.entities = entities,
                               console.error)
    }
}

如何通过Component1Component2更新Service

1 个答案:

答案 0 :(得分:1)

您应该另外观察一下,以减轻组件之间的交流:

@Injectable()
export class StoreService {

  private _employes$ = new BehaviorSubject<{id:number,employee_name:string,employee_salary:number,employee_age:number}[]>([]);

  constructor(private _http: HttpClient) {
    this.refresh();
  }

  refresh() {
    this._http.get<{id:number,employee_name:string,employee_salary:number,employee_age:number}[]>('https://dummy.restapiexample.com/api/v1/employees').subscribe(
      data => this._employes$.next(data)
    );
  }

  post() {
      const payload = {"name":"test","salary":"123","age":"23"};

      this._http.post('https://dummy.restapiexample.com/api/v1/create', payload).subscribe(() => {
        this.refresh();
      })
  }

  get employes$(): Observable<{id:number,employee_name:string,employee_salary:number,employee_age:number}[]> {
    return this._employes$.asObservable();
  }
}

由两部分组成:

商店可观察的用途,当您要更新流时,可以在其旁边。

private _employes$ = new BehaviorSubject<{...}[]>([]);

暴露的吸气剂。需要通过商店中的任何更改通知的任何组件都可以订阅。

  get employes$(): Observable<{...}[]> {
    return this._employes$.asObservable();
  }

从现在开始,所有内容都与您的实际情况有关,您可以通过多种方式来更新此内部可观察到的内容:

最快的方法:

refresh() {
    this._http.get<{...}[]>('...').subscribe(
      data => this._employes$.next(data)
    );
  }

在您的服务内部,您订阅了http呼叫并更新了内部可观察的内容。

专业版:

  • 您不公开请求。
  • 非常容易维护,因为只有一个地方可以进行API调用。

骗局:

  • 不适用于您想要实际控制,更新……对API答案进行特定操作的情况。
  • 订阅服务并不总是一个好主意。

可观察的体操

如果您不想订阅您的服务。您可以执行以下操作:

return this._http.get<{...}[]>('...')
    .pipe(switchMap(result => {
        this._employes$.next(result);
        return this.employes$;
    }));

您将您的http可观察者转换为内部可观察者。同时,您接下来将获得API答案的新结果。

如果明天您需要在API响应中委派特殊特征,然后才能在整个应用程序中使用它。

您可以:

refresh(myCustomTraitment: = null) {
    return this._http.get<{...}[]>('...')
        .pipe(switchMap(result => {
            if (myCustomTraitment) {
                result = result.map(myCustomTraitment);
            }
            this._employes$.next(result);
            return this._employes$;
        }));
}

Online sample