redux observableで、他のアクションの前にアクションを実行するにはどうすればよいですか?

user17472

バックグラウンド:

リクエストの管理にエピックを使用しています。

リクエストごとにトークンを送信します。トークンは期限切れになる可能性がありますが、猶予期間内に更新できます。

すべてのリクエストにトークンを使用していますが、リクエストを送信する前に、トークンの有効期限が切れているかどうかを確認したいと思います。有効期限が切れていて猶予期間がある場合は、最初にトークンを更新してから、対応するアクションに進みます。

すべてのリクエストには独自の叙事詩があります。

今私が試しているのは、トークンをチェックしてトークンを更新してからアクションを続行するためのすべてのアクションの事前フックです。

これが説明することを願っています。

// epics for querying data
// these epics are using a token, that is stored in redux state.

const getMenuEpic = action$ => ....

const getFoodListEpic = action$ => ....

const getFoodItemEpic = action$ => ....

...


// helper function to check 
// if token has expired

const hasTokenExpired = (token) => .....

// refresh token 
// this returns a new token in the promise

const refreshToken = fetch('http://.../refresh-toekn')

// i am trying to make an epic, that will fire 
// before any actions in the application
// stop the action (let's call it action A)
// get token from redux state, 
// verify if is valid or not
// if invalid call refresh token (async process), 
// and when refresh token finished, proceed with the incoming action A
// if the token was valid then continue with action A.

const refreshEpic = (action$, store) => 
 action$.map(() => store.getState().token)
  .filter(Boolean)
  .filter(token => hasTokenExpired(token))
  .mergeMap(() => refreshToken()) ...

 ......

しかし、このアプローチはrefreshEpicでは機能しません

jayphelps

アクションがレデューサーに到達するのを本当に防ぐことはできません-エピックに与えられる前に実際にはすでにレデューサーを通過しています-代わりに、フェッチする意図を示すアクションをディスパッチできますが、実際にはそれをトリガーするものではありません。たとえば、UIはFETCH_SOMETHINGをディスパッチし、エピックはそれを確認し、有効な更新トークンがあることを確認し(または新しいトークンを取得し)、実際にフェッチをトリガーする別のアクションを発行します(例:FETCH_SOMETHING_WITH_TOKEN)。

この特定のケースでは、同じ要件を持つ多くの叙事詩があり、そのようにするのは面倒になる可能性があります。これを簡単にする方法はたくさんあります。ここにいくつかあります:

フェッチをヘルパーでラップします

あなたはあなたのためにチェックをするヘルパーを書くことができます、そしてそれがリフレッシュを必要とするならば、それは先に進む前にそれを要求して待つでしょう。実際の更新は個別の専用エピックで個人的に処理するため、複数の同時更新要求などを防ぐことができます。

const requireValidToken = (action$, store, callback) => {
  const needsRefresh = hasTokenExpired(store.getState().token);

  if (needsRefresh) {
    return action$.ofType(REFRESH_TOKEN_SUCCESS)
      .take(1)
      .takeUntil(action$.ofType(REFRESH_TOKEN_FAILED))
      .mergeMap(() => callback(store.getState().token))
      .startWith({ type: REFRESH_TOKEN });
  } else {
    return callback(store.getState().token);
  }
};

const getMenuEpic = (action$, store) =>
  action$.ofType(GET_MENU)
    .switchMap(() =>
      requireValidToken(action$, store, token =>
        actuallyGetMenu(token)
          .map(response => getMenuSuccess(response))
      )
    );

「超叙事詩」

編集:これは私の最初の提案でしたが、上記のものよりもはるかに複雑です。いくつかの利点もありますが、上記のIMOは使いやすく、保守も簡単です。

代わりに、「スーパーエピック」を作成することもできます。これは、それ自体が構成され、他のエピックに委任されるエピックです。ルートエピックはスーパーエピックの一例です。(私は今その用語を作りました...笑)

おそらくやりたいことの1つは、ランダムアクションと認証トークンを必要とするアクションを区別することです。認証トークンをチェックして、ディスパッチされたすべてのアクションに対して更新する必要はありません。簡単な方法は、アクションにメタデータを含めることです。{ meta: { requiresAuth: true } }

これははるかに複雑ですが、他のソリューションよりも長所があります。これが私が話していることの大まかな考えですが、それはテストされておらず、おそらく100%考え抜かれたものではありません。コピーパスタではなく、インスピレーションと考えてください。

// action creator helper to add the requiresAuth metadata
const requiresAuth = action => ({
  ...action,
  meta: {
    ...action.meta,
    requiresAuth: true
  }
});
// action creators
const getMenu = id => requiresAuth({
  type: 'GET_MENU',
  id
});
const getFoodList = () => requiresAuth({
  type: 'GET_FOOD_LIST'
});

// epics
const getMenuEpic = action$ => stuff
const getFoodListEpic = action$ => stuff

const refreshTokenEpic = action$ =>
  action$.ofType(REFRESH_TOKEN)
    // If there's already a pending refreshToken() we'll ignore the new
    // request to do it again since its redundant. If you instead want to
    // cancel the pending one and start again, use switchMap()
    .exhaustMap(() =>
      Observable.from(refreshToken())
        .map(response => ({
          type: REFRESH_TOKEN_SUCCESS,
          token: response.token
        }))
        // probably should force user to re-login or whatevs
        .catch(error => Observable.of({
          type: REFRESH_TOKEN_FAILED,
          error
        }))
    );


// factory to create a "super-epic" which will only
// pass along requiresAuth actions when we have a
// valid token, refreshing it if needed before.
const createRequiresTokenEpic = (...epics) => (action$, ...rest) => {
  // The epics we're delegating for
  const delegatorEpic = combineEpics(...epics);
  // We need some way to emit REFRESH_TOKEN actions
  // so I just hacked it with a Subject. There is
  // prolly a more elegant way to do this but #YOLO
  const output$ = new Subject();

  // This becomes action$ for all the epics we're delegating
  // for. This will hold off on giving an action to those
  // epics until we have a valid token. But remember,
  // this doesn't delay your *reducers* from seeing it
  // as its already been through them!
  const filteredAction$ = action$
    .mergeMap(action => {
      if (action.meta && action.meta.requiresAuth) {
        const needsRefresh = hasTokenExpired(store.getState().token);

        if (needsRefresh) {
          // Kick off the refreshing of the token
          output$.next({ type: REFRESH_TOKEN });

          // Wait for a successful refresh
          return action$.ofType(REFRESH_TOKEN_SUCCESS)
            .take(1)
            .mapTo(action)
            .takeUntil(action$.ofType(REFRESH_TOKEN_FAILED));
            // Its wise to handle the case when refreshing fails.
            // This example just gives up and never sends the
            // original action through because presumably
            // this is a fatal app state and should be handled
            // in refreshTokenEpic (.e.g. force relogin)
        }
      }

      // Actions which don't require auth are passed through as-is
      return Observable.of(action);
    });

  return Observable.merge(
    delegatorEpic(filteredAction$, ...rest),
    output$
  );
};

const requiresTokenEpic = createRequiresTokenEpic(getMenuEpic, getFoodList, ...etc);

前述のように、この問題に取り組む方法はたくさんあります。この「スーパーエピック」アプローチの代わりにトークンを必要とするエピック内で使用するある種のヘルパー関数を作成することを想像できます。あなたにとってそれほど複雑ではないと思われることをしてください。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

redux-observable epicを使用して2つのアクション間の期間を測定するにはどうすればよいですか?

分類Dev

非同期アクションを実行するReduxでモーダルダイアログを表示するにはどうすればよいですか?

分類Dev

非同期アクションを実行するReduxでモーダルダイアログを表示するにはどうすればよいですか?

分類Dev

Redux Observableで1つのアクションをディスパッチし、1秒待ってから、さらに2つのアクションをディスパッチするにはどうすればよいですか?

分類Dev

redux-observableの場合-アクションの値を返さずにアクションを「ミッドストリーム」でディスパッチするにはどうすればよいですか?

分類Dev

Reduxのストアを更新するアクションを作成するにはどうすればよいですか?

分類Dev

redux-thunkのフェッチアクションから状態にアクセスするにはどうすればよいですか?

分類Dev

リダイレクトが行われた後にアクション(Redux)をディスパッチするにはどうすればよいですか?

分類Dev

Redux-Angular:アクションが2回呼び出されるのを防ぐにはどうすればよいですか?

分類Dev

Typescriptを使用してReduxレデューサー関数内に徹底的なswitchステートメントを実装するにはどうすればよいですか?Reduxの内部@@ reduxアクションを処理する方法

分類Dev

アクションクリエーターからreduxストアにアクセスするにはどうすればよいですか?

分類Dev

別のアクションが正しくディスパッチされた場合にアクションをディスパッチするにはどうすればよいですか?redux thunk(react)を使用する

分類Dev

React-Redux-子コンポーネントからアクションをディスパッチするにはどうすればよいですか?

分類Dev

ReactアプリケーションでReduxストアの一部のみをロードするにはどうすればよいですか?

分類Dev

多次元オブジェクトにReduxアクションを使用するにはどうすればよいですか?

分類Dev

アクションを再利用可能にするにはどうすればよいですか?Reduxを使用したReactJS

分類Dev

reduxを使用してアクション間に依存関係を追加するにはどうすればよいですか?

分類Dev

TypeScriptタイプセーフティをreduxアクションに追加するにはどうすればよいですか?

分類Dev

onClick属性に引数を取るreduxアクションを割り当てるにはどうすればよいですか?

分類Dev

redux状態の更新後にどのようにアクションを実行しますか?

分類Dev

reduxアクションを置き換えてcreateactionsライブラリを使用するにはどうすればよいですか?

分類Dev

アクション情報をコンポーネント、React + Reduxに渡すにはどうすればよいですか?

分類Dev

reduxアクションをディスパッチするネストされたコンポーネントのイベントバブリングを停止するにはどうすればよいですか?

分類Dev

reduxアクションから別の2つの関数を呼び出すreactjsで関数を非同期にするにはどうすればよいですか?

分類Dev

アクションが呼び出されたときに、react reduxの配列内のオブジェクトの値を変更するにはどうすればよいですか?

分類Dev

何かを実行する前に 2 つのアクションを待機する redux で観察可能なエピックを作成する方法

分類Dev

redux-sagaに2つのアクションが少なくとも1回、任意の順序で発生するのを待つにはどうすればよいですか?

分類Dev

reduxツールキットで複数のディスパッチを使用してアクションクリエーターを変換するにはどうすればよいですか?

分類Dev

なぜngrx / reduxエフェクトはアクションを返さなければならないのですか?elmのようなnoopアクションを使用することは悪い習慣と見なされますか?

Related 関連記事

  1. 1

    redux-observable epicを使用して2つのアクション間の期間を測定するにはどうすればよいですか?

  2. 2

    非同期アクションを実行するReduxでモーダルダイアログを表示するにはどうすればよいですか?

  3. 3

    非同期アクションを実行するReduxでモーダルダイアログを表示するにはどうすればよいですか?

  4. 4

    Redux Observableで1つのアクションをディスパッチし、1秒待ってから、さらに2つのアクションをディスパッチするにはどうすればよいですか?

  5. 5

    redux-observableの場合-アクションの値を返さずにアクションを「ミッドストリーム」でディスパッチするにはどうすればよいですか?

  6. 6

    Reduxのストアを更新するアクションを作成するにはどうすればよいですか?

  7. 7

    redux-thunkのフェッチアクションから状態にアクセスするにはどうすればよいですか?

  8. 8

    リダイレクトが行われた後にアクション(Redux)をディスパッチするにはどうすればよいですか?

  9. 9

    Redux-Angular:アクションが2回呼び出されるのを防ぐにはどうすればよいですか?

  10. 10

    Typescriptを使用してReduxレデューサー関数内に徹底的なswitchステートメントを実装するにはどうすればよいですか?Reduxの内部@@ reduxアクションを処理する方法

  11. 11

    アクションクリエーターからreduxストアにアクセスするにはどうすればよいですか?

  12. 12

    別のアクションが正しくディスパッチされた場合にアクションをディスパッチするにはどうすればよいですか?redux thunk(react)を使用する

  13. 13

    React-Redux-子コンポーネントからアクションをディスパッチするにはどうすればよいですか?

  14. 14

    ReactアプリケーションでReduxストアの一部のみをロードするにはどうすればよいですか?

  15. 15

    多次元オブジェクトにReduxアクションを使用するにはどうすればよいですか?

  16. 16

    アクションを再利用可能にするにはどうすればよいですか?Reduxを使用したReactJS

  17. 17

    reduxを使用してアクション間に依存関係を追加するにはどうすればよいですか?

  18. 18

    TypeScriptタイプセーフティをreduxアクションに追加するにはどうすればよいですか?

  19. 19

    onClick属性に引数を取るreduxアクションを割り当てるにはどうすればよいですか?

  20. 20

    redux状態の更新後にどのようにアクションを実行しますか?

  21. 21

    reduxアクションを置き換えてcreateactionsライブラリを使用するにはどうすればよいですか?

  22. 22

    アクション情報をコンポーネント、React + Reduxに渡すにはどうすればよいですか?

  23. 23

    reduxアクションをディスパッチするネストされたコンポーネントのイベントバブリングを停止するにはどうすればよいですか?

  24. 24

    reduxアクションから別の2つの関数を呼び出すreactjsで関数を非同期にするにはどうすればよいですか?

  25. 25

    アクションが呼び出されたときに、react reduxの配列内のオブジェクトの値を変更するにはどうすればよいですか?

  26. 26

    何かを実行する前に 2 つのアクションを待機する redux で観察可能なエピックを作成する方法

  27. 27

    redux-sagaに2つのアクションが少なくとも1回、任意の順序で発生するのを待つにはどうすればよいですか?

  28. 28

    reduxツールキットで複数のディスパッチを使用してアクションクリエーターを変換するにはどうすればよいですか?

  29. 29

    なぜngrx / reduxエフェクトはアクションを返さなければならないのですか?elmのようなnoopアクションを使用することは悪い習慣と見なされますか?

ホットタグ

アーカイブ