【问题标题】:Force subscribers to re-request data from Service?强制订阅者从服务重新请求数据?
【发布时间】:2020-04-01 18:56:41
【问题描述】:

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

服务

@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));
  }
}

组件0

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

组件1

@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)
    }
}

组件2

@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)
    }
}

如何让Component1 通过Service 更新Component2

【问题讨论】:

  • 您希望这样,每当您在comp1 上提交时(也就是说,向与comp2entities 属性无关的数据库发送post 请求)它应该更新@ comp2 上的 987654337@,对吗?
  • 刚刚添加了一个StackBlitz 链接。对,那是正确的。可能是我不打算拥有comp2entities 属性,可能是我在服务中存储了一些东西,可能是我使用BehaviourSubjectSubject 而不是松散的大批。如何以可维护的方式处理这种常见情况?

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


【解决方案1】:

你应该有另一个 observable 来减轻你的组件通信:

@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();
  }

从现在开始,一切都与你的实际情况有关,你有多种方法来更新这个内部 observable:

最快的方法:

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

在您的服务中,您订阅您的 http 调用并更新您的内部 observable。

专业版:

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

缺点:

  • 不适用于您希望实际控制、更新、...使用 API 答案执行特定操作的情况。
  • 订阅服务并不总是一个好主意。

可观察体操

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

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

您将 http get observable 转换为内部 observable。同时你下一个你的 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-26
    • 2021-08-29
    • 1970-01-01
    • 2012-06-03
    • 2017-05-21
    • 2019-07-14
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多