36

ngrx/store 1.5 とサンク ミドルウェアを使用するアプリケーションで作業しており、ngrx/store 2.0 と ngrx/effects に移行しようとしています。関連する複数のアクションや効果を処理する方法についていくつか質問があります。

サンクとエフェクトの「考え方」が異なることに気づき、その違いを理解しようとしています。私は利用可能なサンプルアプリを調べましたが、私が試みているものに合うと思われるものを見つけられなかったので、おそらく私はまだ完全に間違っています.

シナリオ 1

以下は、サーバーへのログイン要求を処理するための副作用です。

@Effect login$: any = this.updates$
    .whenAction(LoginActions.LOGIN)
    .map(toPayload)
    .switchMap(payload => 
        this.loginService.login(payload.user, payload.password)
            .map(result => this.actions.loginSuccess(value))
            .catch((error) => Observable.of(this.loginError(error)))
));

その最初の副作用を考えると、ログインに成功したときに「ホーム」画面へのナビゲーションをトリガーする「正しい」または「推奨される」方法は何でしょうか? これは、一連のアクションまたは操作を単純にトリガーするために一般化することもできます。

私が検討したいくつかのオプション:

(a) ログインの成功によってトリガーされる別の効果で、後続のアクションを起動してナビゲーションをトリガーしますか?

@Effect navigateHome$: any = this.updates$
    .whenAction(LoginActions.LOGIN_SUCCEEDED)
    .mapTo(this.actions.navigateHome());

(b) ログインの成功によって引き起こされる、単純にナビゲーション操作を実行する別の効果?

@Effect navigateHome$: any = this.updates$
    .whenAction(LoginActions.LOGIN_SUCCEEDED)
    .do(this.navigateHome())
    .filter(() => false);

(c) 最初のログイン効果によって発行されたアクションに追加のアクションを連結しますか? (サンプルは明らかに正確ではありませんが、アイデアを提供します)

@Effect login$: any = this.updates$
    .whenAction(LoginActions.LOGIN)
    .map(toPayload)
    .switchMap(password => Observable.concat(
        this.loginService.login(passcode)
            .map(result => this.actions.loginSuccess(value))
            .catch((error) => Observable.of(this.loginError(error))),
        Observable.of(this.actions.navigateHome())
    ));

(d) その他?

シナリオ 2

多数のリクエストを順番に行う必要があり、リクエストが始まるたびに「ステータス」を更新して、ユーザーにフィードバックを提供できるようにしたい場合を考えてみましょう。

これらの行に沿った何かのサンクの例:

multiphaseAction() {
    return (dispatch) => {
        dispatch(this.actions.updateStatus('Executing phase 1');
        this.request1()
            .flatMap(result => {
                dispatch(this.actions.updateStatus('Executing phase 2');
                return this.request2();
            })
            .flatMap(result => {
                dispatch(this.actions.updateStatus('Executing phase 3');
                return this.request3();
            })
            ...
    }
}

繰り返しますが、効果アプローチを使用する際にこれを行うための「正しい」または「推奨される」方法は何でしょうか?

これは私がもっとこだわっていますが、何とか追加する以外に何ができるのか本当にわかりません.do(this.store.dispatch(this.actions.updateStatus(...))...

4

4 に答える 4

20

ナビゲーションシナリオの答えはあなたのbの答えです

@Effect navigateHome$: any = this.updates$
    .whenAction(LoginActions.LOGIN_SUCCEEDED)
    .do(this.router.navigate('/home'))
    .ignoreElements();

説明: LOGIN_SUCCESS に反応しますが、ルーターが新しいアクションを返さないため、ストリームの伝播を停止する必要があります。これは、すべてをフィルタリングすることによって行われます。

フィルタリングを忘れると、ルーターは undefined を返します。これにより、reducer が未定義の値を減らすことになりtype、アクションの

それを解決する別の方法は、https://github.com/ngrx/router-storeを使用することです

アプリに router-store を追加する方法については、ドキュメントを確認してください。

同じ効果が次のようになります。

import { go } from '@ngrx/router-store';

@Effect navigateHome$: any = this.updates$
    .whenAction(LoginActions.LOGIN_SUCCEEDED)
    .map(() => go(['/home']));

このgoアクションは、ルーター レデューサーがピックアップしてルート変更をトリガーするルーター アクションをディスパッチします。

于 2016-06-21T06:22:06.250 に答える
2

シナリオ 1

navigateHome状態を変更する必要があるかどうかを検討してください。navigateHomeまた、このアクションが同じことを達成するために他の場所からディスパッチされるかどうか。もしそうなら、アクションを返すことが道です。したがって、オプション A。

場合によっては、オプション B の方が理にかなっています。ルート変更だけならnavigateHome検討の価値ありかも。

補足:の代わりにここでignoreElementsfilter(() => false)を使用できます。

シナリオ 2

ここでアクションを複数の効果に連鎖させ、アクションごとにレデューサーの状態を変更してフィードバックを提供することをお勧めします。

例えば:

@Effect() trigger$: Observable<Action> = this.updates$
    .whenAction(Actions.TRIGGER)
    .do(() => console.log("start doing something here"))
    .mapTo(Actions.PHASE1);

@Effect() phase1$: Observable<Action> = this.updates$
    .whenAction(Actions.PHASE1)
    .do(() => console.log("phase 1"))
    .mapTo(Actions.PHASE2);

@Effect() phase2$: Observable<Action> = this.updates$
    .whenAction(Actions.PHASE2)
    .do(() => console.log("phase 2"))
    .ignoreElements();

状態を変更してフィードバックを提供します。

function reducer(state = initialState, action: Action): SomeState {
    switch (action.type) {
        case Actions.TRIGGER: {
            return Object.assign({}, state, {
                triggered: true
            });
        }
        case Actions.PHASE1: {
            return Object.assign({}, state, {
                phase1: true
            });
        }
        case Actions.PHASE2: {
            return Object.assign({}, state, {
                phase1: false,
                phase2: true
            });
        }
        // ...
    }
}
于 2016-06-28T09:06:48.833 に答える
0

シナリオ 1

オプション A と B はどちらも良いと思いますが、オプション A はナビゲーションには少し多すぎるかもしれません! LoginActions.LOGINナビゲーションをこの副作用の一部と見なす場合は、ルーターを直接使用することもできます。

シナリオ 2

チェーンアップしても問題はありません@Effects。エフェクト A をトリガーするアクション (SET_1_REQUEST) をディスパッチします。エフェクト A は、リデューサーによってピックアップされるアクション (SET_1_SUCCESS) を返し (ユーザーにそのステータスを表示できるようになりました)、エフェクト B によってピックアップされます。

これが理にかなっていることを願っています。

于 2016-06-21T06:21:46.917 に答える