2017-01-12 59 views
2

我開始考慮ngrx/Store,我正面臨以下問題。ngrx商店 - 如何在用戶界面中管理潛在的長時間操作

從我的UI組件中,我需要執行對遠程rest API的調用,這可能需要一些時間才能執行。我想管理顯示用戶標準加載微調器的等待時間。

我習慣在上面的代碼片斷代碼,看起來像

let loading = this.loadingCtrl.create({ 
      content: 'Please wait while we load stuff' 
     }); 
    loading.present(); 
    this.longRunningService.doHeavyWork() 
      .subscribe(
       (result) => { 
           // manage result; 
          }, 
       (err) => console.log(err), 
      () => loading.dismiss() 
     ); 

關鍵點(我的問題)來管理這樣的情況是,當longRunningService完成doHeavyWork邏輯(即當可觀察完成)加載微調器被解僱。

現在我想重構這個代碼,並使用NGRX /商店派遣機制。

我的問題是如何管理loading.dismiss()邏輯,同時使用ngrx/Storedispatch機制。換句話說,我不知道如何使用ngrx/Store調度動作機制來關閉加載微調器(一旦從後端休息API接收到結果)的

任何意見是非常讚賞

+1

看一看[這個答案](http://stackoverflow.com/a/40496998/6680611),並看看[NGRX /效果](https://github.com/ngrx/effects) – cartant

回答

3

您需要添加ngrx/effects庫處理的副作用,如「longRunningService」

我學這個從NGRX官方例子。我建議你看看 https://github.com/ngrx/example-app

下面的代碼是基於示例應用程序和處理加載的東西,請檢查它。

我假設你正在編寫離子v2應用程序?因爲LoadingController的..

操作:

export const LOAD_STUFF = "LOAD_STUFF"; 
export const LOAD_STUFF_SUCCESS = "LOAD_STUFF_SUCCESS"; 
export const LOAD_STUFF_FAIL = "LOAD_STUFF_FAIL"; 

@Injectable() 
export class StuffActions{ 

    loadStuff() : Action { 
    return { 
     type: LOAD_STUFF 
    }; 
    } 

    loadStuffSuccess(stuff : any []) : Action { 
    return { 
     type: LOAD_STUFF_SUCCESS, 
     payload: stuff 
    }; 
    } 
} 

減速

export interface State { 
    entities: []; 
    loading : boolean; 
    complete : boolean; 
} 

const initalState : State = { 
    entities: []; 
    loading : false; 
    complete : false; 
}; 

export function reducer(state = initalState, action) : State { 
    switch (action.type) { 

    case LOAD_STUFF: 
     return Object.assign({}, state, { 
     loading: true, 
     complete: false 
     }); 

    case LOAD_STUFF_SUCCESS: 
     return { 
     complete: true, 
     loading: false, 
     entities : action.payload 
     }; 

    default: 
     return state; 
    } 
} 

// SELECTORS 
export const getLoading = (state: State) => state.loading; 
export const getComplete = (state: State) => state.complete; 
export const getEntities = (state: State) => state.stuff; 

效果

@Injectable() 
export class EnvioEffects { 
    constructor(private actions$: Actions, private _stuffActions : StuffActions, private _longRunningService: LongRunningService){} 

    @Effect() loadStuff: Observable<Action> = this.actions$ 
    .ofType(LOAD_STUFF) 
    .switchMap(() => this._longRunningService.getStuff()) 
    .map(stuff => this._stuffActions.loadStuffSuccess(stuff)); 

}

選擇指數。對於選擇我用https://github.com/reactjs/reselect

import * as fromStuff from "./stuff"; 
import {createSelector} from "reselect"; 
import {ActionReducer, combineReducers, Action} from "@ngrx/store";  

export interface State { 
    stuff: fromStuff.State 
} 

const reducers = { 
    stuff: fromStuff.reducer 
}; 

export const reducer: ActionReducer<State> = combineReducers(reducers); 

export const rootReducer = (state: State, action: Action) => { 
    return reducer(state, action); 
}; 

export const getStuffEntities = createSelector(getOriginState, fromStuff.getEntities); 
export const getStuffLoading = createSelector(getOriginState, fromOrigin.getLoading); 
export const getStuffComplete = createSelector(getOriginState, fromOrigin.getComplete); 

import * as fromRoot from "../../reducers/index"; 

@Component({ 
    selector: 'stuff', 
    templateUrl: 'stuff.html' 
}) 
export class StuffPage implements OnDestroy { 

    destroy$: Subject<any> = new Subject(); 

    constructor(public navCtrl: NavController, 
       public loadingCtrl: LoadingController, 
       private _store: Store<fromRoot.State>, 
       private _stuffActions: StuffActions) { 
    } 


    ionViewDidLoad() { 
    // HERE I SHOW THE LOADING ANIMATION UNTIL THE LONG RUNNING SERVICE COMPLETE 
    this._store.select(fromRoot.getStuffLoading) 
     .takeUntil(this.destroy$) 
     .filter(isloading => isloading) 
     .map(() => this.createLoader()) 
     .do(loading => loading.present()) 
     .delayWhen(loading => this._store.select(fromRoot.getStuffComplete).filter(complete => complete)) 
     .map(loading => loading.dismiss()) 
     .subscribe(); 

    // LOAD THE STUFF 
    this._store.dispatch(this._stuffActions.loadStuff()); 

    } 

    createLoader(): Loading { 
    return this.loadingCtrl.create({ 
     content: "Loading stuff" 
    }); 
    } 

    ngOnDestroy() { 
    this.destroy$.next(); 
    this.destroy$.unsubscribe(); 
    } 
}