2017-02-21 73 views
8

我對ngrx和Redux風格體系結構很陌生,而且我在理解如何鏈接動作/效果時遇到問題。一個例子就是實現基本的功能,比如在用戶登錄後採取行動。我的核心焦點在於,用戶登錄後採取的行動將取決於應用程序的當前狀態 - 用戶可能在任何地方在應用程序中提供登錄提示/頁面時。ngrx鏈接操作/效果 - 例如,登錄然後導航

任何示例我已經看到硬編碼效果,一旦用戶登錄就會發生。在我的情況下,這並不適合如上所述,我並不總是希望發生同樣的動作。

以下是包含登錄組件的主頁的一些示例代碼。在這種情況下,我想用戶重定向到/買入「一旦他們在已登錄

@Component(..) 
export class HomePageComponent { 
    constructor(private store: Store<any>) { 
    } 

    public onLoginSubmitted(username, password) { 
     this.store.dispatch(new loginActions.Login({username, password})); 
     // once this has happened successfully navigate to /buy  
    } 

} 

例效果

@Injectable() 
export class LoginEffects { 

    ......  

    @Effect() 
    login$ = this.actions$ 
     .ofType(loginActions.ActionTypes.LOGIN) 
     .switchMap((data) => { 
      return this.loginService.login(data.payload) 
       .map(() => new loginActions.LoginSuccess({loggedIn: true, isLoggingIn: false})) 
       .catch((error) => { 
        return of(new loginActions.LoginError({loggedIn: false, isLoggingIn: false})); 
       }); 
     }); 
    ...... 
} 

我對你會如何解決這個問題的幾點思考 - 但他們都沒有感覺正確。這些包括

  • 傳遞數據與登錄有效載荷,以確定要採取的動作下
  • 寫作大量的,其在LoginSuccess採取行動,但在一些較高的水平
  • 被過濾通過聽寫成分特異性作用效果到商店的事件(這是可能/不好的做法?)
  • 從商店讀取有關當前登錄狀態的數據並在組件中採取行動。然而,這種邏輯會立即運行,這可能不會產生預期的效果

任何人都可以指出我正確的道路/目前的例子,這應該如何解決?

+0

有效負載的一部分可能是'redirectRoute',然後登錄後,'LoginSuccess'效果將根據'redirectRoute'指定的位置進行導航。你只有一個'loginSuccess'動作,但它可以重定向到任何地方。 – Adam

+0

它可能是 - 但是這假設你將永遠想在登錄後重定向。這可能不一定是這種情況,例如,您可能想要解僱我喜歡此解決方案的模式 – dannym

回答

9

效果可以在一系列操作上使用mergeMap來觸發多個操作。我通常會做的是,傳入我希望登錄效果也可以發送的附加操作。

@Component(..) 
export class HomePageComponent { 
    constructor(private store: Store<any>) { } 

    public onLoginSubmitted(username, password) { 
     this.store.dispatch(new loginActions.Login({ 
      username, 
      password, 
      onCompleteActions: [new loginActions.Redirect({ route: '/buy' })] })); 
    } 
} 

登錄效果然後會使用mergeMap發送任何傳入的操作。您仍然必須爲每個操作創建一個效果,但現在可以構建更多可重用操作,例如重定向操作。

@Injectable() 
export class LoginEffects { 

    ......  

    @Effect() 
    login$ = this.actions$ 
     .ofType(loginActions.ActionTypes.LOGIN) 
     .switchMap((data) => { 
      let mappedActions = [new loginActions.LoginSuccess({loggedIn: true, isLoggingIn: false})]; 
      if (data.payload.onCompleteActions) 
       mappedActions = mappedActions.concat(data.payload.onCompleteActions); 

      return this.loginService.login(data.payload) 
       .mergeMap(mappedActions) 
       .catch((error) => { 
        return of(new loginActions.LoginError({loggedIn: false, isLoggingIn: false})); 
       }); 
     }); 

    ...... 
} 

我喜歡這個解決方案是什麼,它是可升級的未來,因爲任何操作都可以通過在,而且也沒有開關或的if-else樹來決定做什麼。您還可以傳入多個操作,因此不需要構建「redirectAndCloseModal」操作,您可以傳入redirect以及closeModal

this.store.dispatch(new loginActions.Login({ 
    username, 
    password, 
    onCompleteActions: [new loginActions.Redirect({ route: '/buy' }), new modalActions.CloseModal()] })); 

你可以閱讀一些有關dispatching multiple Actions from one @Effect() at this github issue.

編輯:關於你的評論,它不只是路線的變化,可能使你想停止登錄,它可以是任何東西,如關閉一個模式,並沒有通用的方式來觀察。您可以添加一些東西到您的商店,例如runLoginActions布爾值,然後在登錄請求返回後從商店中讀取該數據。

然後在您的login$效果中,您可以從商店中讀取它以決定是否運行其他操作。

@Effect() 
login$: Observable<Action> = this.actions$ 
    .ofType(auth.actionTypes.LOGIN) 
    .map((action: auth.LoginAction) => action.payload) 
    .switchMap((user) => { 
     let successAction = new loginActions.LoginSuccess({loggedIn: true, isLoggingIn: false}); 
     let mappedActions = [successAction]; 
     if (data.payload.onCompleteAction) 
      mappedActions.push(data.payload.onCompleteAction); 

     return this.authService.login(user.username, user.password) 
      .withLatestFrom(this.store) 
      .mergeMap(([result, store]) => store.runLoginActions ? 
       [mappedActions] : 
       [successAction] 
      ) 
      .catch((err) => { 
       try { 
        return of(new auth.NetworkFailureAction(err[0].code)); 
       } catch (e) { 
        throw `Array not in the expected format of [{ code: "", message: "" }]`; 
       } 
      }); 
    }); 

注意,在你減速的loginSuccess,你應該設置你的runLoginActions = true,它應該是默認啓動爲真,只有當路由改變被關閉或部分被破壞。

請記住,這是一個通用的解決方案,你會需要自己添加的行動,更新減速等

這是一個更大的手工工藝,但由於你的情況不想要執行操作非常具體,可能需要這樣做。

+0

。我有一個問題,如果這些行動可以被取消?例如,用戶厭倦了等待登錄完成並在其他地方導航,我們可能想要取消一旦登錄呼叫返回時發生的重定向 – dannym

+0

您是否想要取消登錄?服務器仍然會被告知用戶已經登錄,但是現在角度客戶端已經忽略了該響應並且不與服務器同步。無論哪種方式,我正在考慮這一點,因爲我不確定答案 – Adam

+0

您可能不想取消登錄,但是您可能想要在稍後取消重定向。這是一種情況 - 用戶轉到主頁。在主頁上有一個登錄表單和一個FAQ按鈕。用戶輸入詳細信息並單擊登錄。處理請求時,他們感到無聊,然後點擊常見問題按鈕,進入常見問題解答頁面並開始閱讀常見問題解答。一旦您的登錄請求返回,您現在不想重定向用戶。 – dannym