我在Angular 4應用中實現ngrx。 REDX相關部分的代碼結構基於來自ngrx repo的示例應用程序(https://github.com/ngrx/example-app)。現在我想知道如何實現這樣的事情:Angular/w ngrx - 連續API調用
- 我已經有一些形式的實體。
- 在提交時,我只向該API發送POST請求,並且只有該實體的名稱。
- 作爲迴應,我得到新創建實體的ID。
- 緊接着,我想發送第二個請求,其餘的表單值和我剛剛得到的ID。
我應該在哪裏以及如何提出第二個請求?
我在Angular 4應用中實現ngrx。 REDX相關部分的代碼結構基於來自ngrx repo的示例應用程序(https://github.com/ngrx/example-app)。現在我想知道如何實現這樣的事情:Angular/w ngrx - 連續API調用
我應該在哪裏以及如何提出第二個請求?
如何實現連續的API調用取決於調用應該如何一致。
我的意思是,您是否將這兩個電話視爲單個'交易',其中兩個請求都必須成功才能成功更改您的狀態。
顯然,如果第一個請求失敗,第二個請求將無法啓動,因爲它取決於來自第一個請求的數據。 但是...
當第一個請求成功並且第二個請求失敗時會發生什麼?
您的應用能否繼續使用第一個請求中的id
而沒有第二個請求,還是最終處於不一致的狀態?
我將涵蓋兩種情況:
由於兩個請求必須成功,如果他們只有一個要求,你可以查看這兩個請求。 在這種情況下,我建議隱藏服務中的連續調用(這種做法是不特定於NGRX /終極版,它只是普通的RxJs):
@Injectable()
export class PostService {
private API_URL1 = 'http://your.api.com/resource1';
private API_URL2 = 'http://your.api.com/resource2';
constructor(private http: Http) { }
postCombined(formValues: { name: string, age: number }): Observable<any> {
return this.http.post(this.API_URL1, { name: formValues.name })
.map(res => res.json())
.switchMap(post1result =>
this.http.post(this.API_URL2, {
/* access to post1result and formValues */
id: post1result.id,
age: formValues.age,
timestamp: new Date()
})
.map(res => res.json())
.mergeMap(post2result => Observable.of({
/* access to post1result and post2result */
id: post1result.id,
name: post1result.name,
age: post2result.age,
timestamp: post2result.timestamp
})
);
}
}
現在你可以使用postCombined
- 方法中的作用就像在ngrx-example-app中展示的任何其他服務方法一樣。
mergeMap
內定義的數據。如您所見,可以從兩個請求響應中返回合併數據。通過這種方法可以區分這兩個請求的結果,如果任何一個失敗,做出不同的反應。 我建議將這兩個調用分解爲獨立的操作,以便您可以獨立地減少每個案例。
第一,服務現在有兩個獨立的方法(這裏沒有什麼特別):
post.service.ts
@Injectable()
export class PostService {
private API_URL1 = 'http://your.api.com/resource1';
private API_URL2 = 'http://your.api.com/resource2';
constructor(private http: Http) { }
post1(formValues: { name: string }): Observable<{ id: number }> {
return this.http.post(this.API_URL1, formValues).map(res => res.json());
}
post2(receivedId: number, formValues: { age: number }): Observable<any> {
return this.http.post(this.API_URL2, {
id: receivedId,
age: formValues.age,
timestamp: new Date()
})
.map(res => res.json());
}
}
下一個定義兩種請求 - ,成功 - 和失敗,行動要求:
post.actions.ts
import { Action } from '@ngrx/store';
export const POST1_REQUEST = 'POST1_REQUEST';
export const POST1_SUCCESS = 'POST1_SUCCESS';
export const POST1_FAILURE = 'POST1_FAILURE';
export const POST2_REQUEST = 'POST2_REQUEST';
export const POST2_SUCCESS = 'POST2_SUCCESS';
export const POST2_FAILURE = 'POST2_FAILURE';
export class Post1RequestAction implements Action {
readonly type = POST1_REQUEST;
constructor(public payload: { name: string, age: number }) { }
}
export class Post1SuccessAction implements Action {
readonly type = POST1_SUCCESS;
constructor(public payload: { id: number }) { }
}
export class Post1FailureAction implements Action {
readonly type = POST1_FAILURE;
constructor(public error: any) { }
}
export class Post2RequestAction implements Action {
readonly type = POST2_REQUEST;
constructor(public payload: { id: number, name: string, age: number}) { }
}
export class Post2SuccessAction implements Action {
readonly type = POST2_SUCCESS;
constructor(public payload: any) { }
}
export class Post2FailureAction implements Action {
readonly type = POST2_FAILURE;
constructor(public error: any) { }
}
export type Actions
= Post1RequestAction
| Post1SuccessAction
| Post1FailureAction
| Post2RequestAction
| Post2SuccessAction
| Post2FailureAction
現在,我們可以定義當請求行動出動,將運行並反過來將派遣要麼成功 - 或者失敗,行動依賴於服務調用的結果,兩種效應:
post.effects .TS
import { PostService } from '../services/post.service';
import * as post from '../actions/post';
@Injectable()
export class PostEffects {
@Effect()
post1$: Observable<Action> = this.actions$
.ofType(post.POST1_REQUEST)
.map(toPayload)
.switchMap(formValues => this.postService.post1(formValues)
.mergeMap(post1Result =>
Observable.from([
/*
* dispatch an action that signals that
* the first request was successful
*/
new post.Post1SuccessAction(post1Result),
/*
* dispatch an action that triggers the second effect
* as payload we deliver the id we received from the first call
* and any other values the second request needs
*/
new post.Post2RequestAction({
id: post1Result.id,
name: formValues.name,
age: formValues.age
})
])
)
.catch(err => Observable.of(new post.Post1FailureAction(err)))
);
@Effect()
post2$: Observable<Action> = this.actions$
/*
* this effect will only run if the first was successful
* since it depends on the id being returned from the first request
*/
.ofType(post.POST2_REQUEST)
.map(toPayload)
.switchMap(formValuesAndId =>
this.postService.post2(
/* we have access to the id of the first request */
formValuesAndId.id,
/* the rest of the form values we need for the second request */
{ age: formValuesAndId.age }
)
.map(post2Result => new post.Post2SuccessAction(post2Result))
.catch(err => Observable.of(new post.Post2FailureAction(err)))
);
constructor(private actions$: Actions, private postService: PostService) { }
}
通知的mergeMap
結合在第一效Observable.from([..])
。它允許你發送Post1SuccessAction
,可以減少(通過reducer)以及Post2RequestAction
,這會觸發第二個效果運行。如果第一個請求失敗,第二個請求將不會運行,因爲Post2RequestAction
未被分派。
正如您所看到的,通過這種方式設置動作和效果,您可以獨立於其他請求來響應失敗的請求。
要開始第一個請求,您需要做的就是在您提交表單時發送Post1RequestAction
。例如,像this.store.dispatch(new post.Post1RequestAction({ name: 'Bob', age: 45 }))
一樣。