我沒有找到任何關於這個庫的有用信息,或者它的目的是什麼。 看起來像ngrx/effects向已經知道這個概念的開發者解釋這個庫,並給出了一個關於如何編碼的重要示例。ngrx/effects庫的目的是什麼?
我的問題:
- 什麼是行動的來源?
- ngrx/effects庫的目的是什麼;僅使用ngrx/store有什麼缺點?
- 什麼時候推薦使用?
- 它支持角度rc 5+嗎?我們如何在rc 5+中配置它?
謝謝!
我沒有找到任何關於這個庫的有用信息,或者它的目的是什麼。 看起來像ngrx/effects向已經知道這個概念的開發者解釋這個庫,並給出了一個關於如何編碼的重要示例。ngrx/effects庫的目的是什麼?
我的問題:
謝謝!
主題太寬。它將像一個教程。我會試一試。在正常情況下,你會有行動,減速器和商店。行爲由存儲器分發,由reducer訂閱,然後reducer對行爲進行操作,形成一個新狀態。對於教程,所有狀態都在前端,但在真實應用程序中,它需要調用後端數據庫或MQ等,這些調用具有副作用,以將這些效果分解到一個共同的地方,即用於的框架。
假設要將人員記錄保存到數據庫action: Action = {type: SAVE_PERSON, payload: person}
。通常組件不會直接調用this.store.dispatch({type: SAVE_PERSON, payload: person})
讓Reducer調用HTTP服務,而是調用this.personService.save(person).subscribe(res => this.store.dispatch({type: SAVE_PERSON_OK, payload: res.json}))
。如果考慮現實生活中的錯誤處理,組件邏輯將變得更加複雜。爲了避免這種情況,只要從組件中調用 this.store.dispatch({type: SAVE_PERSON, payload: person})
就會很好。
這是效果庫來的。它就像減速器前面的JEE servlet過濾器一樣。它匹配ACTION類型(過濾器可以匹配java世界中的URL),然後對其執行操作,最後返回一個不同的動作,或者不執行動作或多個動作,然後減少對效果輸出動作的響應。
繼續以往的例子,在特效庫方式:
@Effects() savePerson$ = this.stateUpdates$.whenAction(SAVE_PERSON)
.map<Person>(toPayload)
.switchMap(person => this.personService.save(person))
.map(res => {type: SAVE_PERSON_OK, payload: res.json})
.catch(e => {type: SAVE_PERSON_ERR, payload: err})
的編織邏輯集中到所有影響和減縮類。它可以很容易地變得更加複雜,同時這種設計使得其他部件更加簡單並且更加可重用。
例如,如果UI具有自動保存和手動保存,爲了避免不必要的保存,UI自動保存部分可以由定時器觸發,手動部分由用戶點擊觸發,兩者都在效果攔截器中調度SAVE_CLIENT動作,它可以是:
@Effects() savePerson$ = this.stateUpdates$.whenAction(SAVE_PERSON)
.debounce(300).map<Person>(toPayload)
.distinctUntilChanged(...)
.switchMap(see above)
// at least 300 milliseconds and changed to make a save, otherwise no save
呼叫
...switchMap(person => this.personService.save(person))
.map(res => {type: SAVE_PERSON_OK, payload: res.json})
.catch(e => Observable.of({type: SAVE_PERSON_ERR, payload: err}))
只有當出現錯誤工作一次。錯誤被拋出後,流已經死了,因爲catch會嘗試外部流。該電話應爲
...switchMap(person => this.personService.save(person).map(res => {type: SAVE_PERSON_OK, payload: res.json})
.catch(e => Observable.of({type: SAVE_PERSON_ERR, payload: err})))
;或者另一種方式:將所有ServiceClasses服務方法更改爲返回ServiceResponse,其中包含服務器端的錯誤代碼,錯誤消息和封裝的響應對象,即
export class ServiceResult {
error: string;
data: any;
hasError(): boolean {
return error != undefined && error != null; }
static ok(data: any): ServiceResult {
let ret = new ServiceResult();
ret.data = data;
return ret;
}
static err(info: any): ServiceResult {
let ret = new ServiceResult();
ret.error = JSON.stringify(info);
return ret;
}
}
@Injectable()
export class PersonService {
constructor(private http: Http) {}
savePerson(p: Person): Observable<ServiceResult> {
return http.post(url, JSON.stringify(p)).map(ServiceResult.ok);
.catch(ServiceResult.err);
}
}
@Injectable()
export class PersonEffects {
constructor(
private update$: StateUpdates<AppState>,
private personActions: PersonActions,
private svc: PersonService
){
}
@Effects() savePerson$ = this.stateUpdates$.whenAction(PersonActions.SAVE_PERSON)
.map<Person>(toPayload)
.switchMap(person => this.personService.save(person))
.map(res => {
if (res.hasError()) {
return personActions.saveErrAction(res.error);
} else {
return personActions.saveOkAction(res.data);
}
});
@Injectable()
export class PersonActions {
static SAVE_OK_ACTION = "Save OK";
saveOkAction(p: Person): Action {
return {type: PersonActions.SAVE_OK_ACTION,
payload: p};
}
... ...
}
一個修正我之前的評論:影響-Class和減速級,如果你有兩個作用級和減速級的反應相同的動作類型,減速級將首先反應,然後再影響-類。這裏是一個例子: 一個組件有一個按鈕,一旦點擊,調用:this.store.dispatch(this.clientActions.effectChain(1));
將由effectChainReducer
處理,然後ClientEffects.chainEffects$
,這會將有效負載從1增加到2;等待500毫秒發射另一個動作:this.clientActions.effectChain(2)
,通過與effectChainReducer
有效載荷= 2,然後ClientEffects.chainEffects$
,它從2增加到3,發射this.clientActions.effectChain(3)
,...,直到其大於10,ClientEffects.chainEffects$
發射this.clientActions.endEffectChain()
,這改變後處理通過effectChainReducer
將商店狀態改爲1000,最後停在這裏。
export interface AppState {
... ...
chainLevel: number;
}
// In NgModule decorator
@NgModule({
imports: [...,
StoreModule.provideStore({
... ...
chainLevel: effectChainReducer
}, ...],
...
providers: [... runEffects(ClientEffects) ],
...
})
export class AppModule {}
export class ClientActions {
... ...
static EFFECT_CHAIN = "Chain Effect";
effectChain(idx: number): Action {
return {
type: ClientActions.EFFECT_CHAIN,
payload: idx
};
}
static END_EFFECT_CHAIN = "End Chain Effect";
endEffectChain(): Action {
return {
type: ClientActions.END_EFFECT_CHAIN,
};
}
static RESET_EFFECT_CHAIN = "Reset Chain Effect";
resetEffectChain(idx: number = 0): Action {
return {
type: ClientActions.RESET_EFFECT_CHAIN,
payload: idx
};
}
export class ClientEffects {
... ...
@Effect()
chainEffects$ = this.update$.whenAction(ClientActions.EFFECT_CHAIN)
.map<number>(toPayload)
.map(l => {
console.log(`effect chain are at level: ${l}`)
return l + 1;
})
.delay(500)
.map(l => {
if (l > 10) {
return this.clientActions.endEffectChain();
} else {
return this.clientActions.effectChain(l);
}
});
}
// client-reducer.ts file
export const effectChainReducer = (state: any = 0, {type, payload}) => {
switch (type) {
case ClientActions.EFFECT_CHAIN:
console.log("reducer chain are at level: " + payload);
return payload;
case ClientActions.RESET_EFFECT_CHAIN:
console.log("reset chain level to: " + payload);
return payload;
case ClientActions.END_EFFECT_CHAIN:
return 1000;
default:
return state;
}
}
使上面的代碼運行時,輸出應爲:
輸出應看起來像:
客戶reducer.ts:51減速器鏈是在級別:1
客戶effects.ts:72效應鏈是在級別:1
客戶reducer.ts:51減速器鏈是在級別:2
客戶effects.ts:72效應鏈是在級別:2
客戶reducer.ts:51減速器鏈是在級別:3
客戶effects.ts:72效應鏈是在級別:3
......
客戶reducer.ts:51減速鏈是在等級:10
客戶effects.ts:72效應鏈處於水平:10
這是一個很好的答案!一個問題 - 你寫了「錯誤被拋出後流失了」 - 錯誤之後爲什麼會死掉?在另一個問題,請看看我的問題在這裏http://codereview.stackexchange.com/questions/141969/designing-redux-state-tree –
感謝您的更新! –
精彩回答!有一件事對我仍然不清楚。所以想象一下,在頁面上有一個按鈕可以保存用戶輸入的一些數據。我調度SOME_DATA_SAVED被一個效果捕獲的動作(減速器不聽它),然後它試圖保存它。如果成功,則調度SOME_DATA_SAVED_OK(類似於錯誤情況),並且減速器捕獲它並將新數據保存到商店。但是,從UI中看不到保存或出錯時顯示成功的合理方法。單擊保存按鈕後,我可以轉到SOME_DATA_SAVED_OK/ERROR,但感覺非常奇怪 – eddyP23
我從https://www.youtube.com/watch?v=cyaAhXHhxgk觀看了這些來自這些ngrx存儲和效果創作者的視頻。對我來說,第一次正確解釋ngrx效應。所以如果你仍然需要包裹頭部,請檢查它。 – trungk18